/* Transmit the frambuffer with buffersize number of bytes to the LEDs * buffersize = (#LEDs / 16) * 24 */ void neomaple_hard_send(uint8_t *buffer, uint32_t size) { // transmission complete flag, indicate that transmission is taking place WS2812_TC = 0; //WS2812_buffer = buffer; // clear all relevant DMA flags dma_clear_isr_bits(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH5); dma_clear_isr_bits(DMA1, DMA_CH7); // configure the number of bytes to be transferred by the DMA controller //dma_set_mem_addr(DMA1, DMA_CH5, WS2812_buffer); dma_set_num_transfers(DMA1, DMA_CH2, size); dma_set_num_transfers(DMA1, DMA_CH5, size); dma_set_num_transfers(DMA1, DMA_CH7, size); // clear all TIM2 flags TIMER2->regs.gen->SR = 0; // enable the corresponding DMA channels dma_enable(DMA1, DMA_CH2); dma_enable(DMA1, DMA_CH5); dma_enable(DMA1, DMA_CH7); // IMPORTANT: enable the TIM2 DMA requests AFTER enabling the DMA channels! timer_dma_enable_req(TIMER2, 1); timer_dma_enable_req(TIMER2, 2); timer_dma_enable_req(TIMER2, 0); /* TIM_DMA_Update */ // preload counter with 29 so TIM2 generates UEV directly to start DMA transfer timer_set_count(TIMER2, 29); // start TIM2 timer_resume(TIMER2); }
dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { /* Grab and clear the ISR bits. */ uint8 status_bits = dma_get_isr_bits(dev, channel); dma_clear_isr_bits(dev, channel); /* If the channel global interrupt flag is cleared, then * something's very wrong. */ ASSERT(status_bits & 0x1); /* If GIF is set, then some other flag should be set, barring * something unexpected (e.g. the user making an unforeseen IFCR * write). */ ASSERT(status_bits != 0x1); /* ISR flags get set even if the corresponding interrupt enable * bits in the channel's configuration register are cleared, so we * can't use a switch here. * * Don't change the order of these if statements. */ if (status_bits & 0x8) { return DMA_TRANSFER_ERROR; } else if (status_bits & 0x2) { return DMA_TRANSFER_COMPLETE; } else if (status_bits & 0x4) { return DMA_TRANSFER_HALF_COMPLETE; } /* If we get here, one of our assumptions has been violated, but * the debug level is too low for the above ASSERTs() to have had * any effect. In order to fail fast, mimic the DMA controller's * behavior when an error occurs. */ dma_disable(dev, channel); return DMA_TRANSFER_ERROR; }
int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) { dma_tube_reg_map *chregs; int ret = preconfig_check(dev, channel, cfg); if (ret < 0) { return ret; } dma_disable(dev, channel); /* Must disable before reconfiguring */ dma_clear_isr_bits(dev, channel); /* For sanity and consistency * with STM32F2. */ chregs = dma_tube_regs(dev, channel); switch (_dma_addr_type(cfg->tube_dst)) { case DMA_ATYPE_PER: ret = config_to_per(chregs, cfg); break; case DMA_ATYPE_MEM: ret = config_to_mem(chregs, cfg); break; default: /* Can't happen */ ASSERT(0); return -DMA_TUBE_CFG_ECFG; } if (ret < 0) { return ret; } chregs->CNDTR = cfg->tube_nr_xfers; return DMA_TUBE_CFG_SUCCESS; }
static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { void (*handler)(void) = dev->handlers[channel - 1].handler; if (handler) { handler(); dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ } }
/** * @brief Discover the reason why a DMA interrupt was called. * * You may only call this function within an attached interrupt * handler for the given channel. * * This function resets the internal DMA register state which encodes * the cause of the interrupt; consequently, it can only be called * once per interrupt handler invocation. * * @brief dev DMA device * @brief channel Channel whose interrupt is being handled. * @return Reason why the interrupt fired. * @sideeffect Clears channel status flags in dev->regs->ISR. * @see dma_attach_interrupt() * @see dma_irq_cause */ dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { uint8 status_bits = dma_get_isr_bits(dev, channel); /* If the channel global interrupt flag is cleared, then * something's very wrong. */ ASSERT(status_bits & BIT(0)); dma_clear_isr_bits(dev, channel); /* ISR flags get set even if the corresponding interrupt enable * bits in the channel's configuration register are cleared, so we * can't use a switch here. * * Don't change the order of these if statements. */ if (status_bits & BIT(3)) { return DMA_TRANSFER_ERROR; } else if (status_bits & BIT(1)) { return DMA_TRANSFER_COMPLETE; } else if (status_bits & BIT(2)) { return DMA_TRANSFER_HALF_COMPLETE; } else if (status_bits & BIT(0)) { /* Shouldn't happen (unless someone messed up an IFCR write). */ throb(); } #if DEBUG_LEVEL < DEBUG_ALL else { /* We shouldn't have been called, but the debug level is too * low for the above ASSERT() to have had any effect. In * order to fail fast, mimic the DMA controller's behavior * when an error occurs. */ dma_disable(dev, channel); } #endif return DMA_TRANSFER_ERROR; }
void loop(void) { toggleLED(); delay(100); dma_channel_reg_map *ch_regs = dma_channel_regs(USART_DMA_DEV, USART_RX_DMA_CHANNEL); if (irq_fired) { USART_HWSER.println("** IRQ **"); while (true) ; } USART_HWSER.print("["); USART_HWSER.print(millis()); USART_HWSER.print("]\tISR bits: 0x"); uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL); USART_HWSER.print((int32)isr_bits, HEX); USART_HWSER.print("\tCCR: 0x"); USART_HWSER.print((int64)ch_regs->CCR, HEX); USART_HWSER.print("\tCNDTR: 0x"); USART_HWSER.print((int64)ch_regs->CNDTR, HEX); USART_HWSER.print("\tBuffer contents: "); for (int i = 0; i < BUF_SIZE; i++) { USART_HWSER.print('\''); USART_HWSER.print(rx_buf[i]); USART_HWSER.print('\''); if (i < BUF_SIZE - 1) USART_HWSER.print(", "); } USART_HWSER.println(); if (isr_bits == 0x7) { USART_HWSER.println("** Clearing ISR bits."); dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL); } irq_fired = 0; }
static inline void dispatch_handler(dma_dev *dev, dma_stream stream) { void (*handler)(void) = dev->handlers[stream].handler; if (handler) { handler(); dma_clear_isr_bits(dev, stream); /* in case handler doesn't */ } }
/* DMA1 Channel7 Interrupt Handler gets executed once the complete framebuffer has been transmitted to the LEDs */ void DMA1_Channel7_IRQHandler(void) { // clear DMA7 transfer complete interrupt flag dma_clear_isr_bits(DMA1, DMA_CH7); // enable TIM2 Update interrupt to append 50us dead period timer_enable_irq(TIMER2, TIMER_UPDATE_INTERRUPT); // disable the DMA channels dma_disable(DMA1, DMA_CH2); dma_disable(DMA1, DMA_CH5); dma_disable(DMA1, DMA_CH7); // IMPORTANT: disable the DMA requests, too! timer_dma_disable_req(TIMER2, 1); timer_dma_disable_req(TIMER2, 2); timer_dma_disable_req(TIMER2, 0); /* TIM_DMA_Update */ }
static void dispatch_handler(dma_stream stream) { #ifdef ISR_PERF t = stopwatch_getticks(); #endif const dma_dev * dev=DMAS[(stream>>4) & 3]; Handler handler = dev->handlers[stream & 0xF]; if (handler) { revo_call_handler(handler, (uint32_t)stream); } dma_clear_isr_bits(stream); /* in case handler doesn't */ #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif }