This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I am trying to use DMA3 to change the source address of DMA1, in order to get DMA1 to write a new configuration block of data to a timer on each trigger. I have the timer ZERO event triggering DMA1 (and toggling a GPIO) and this seems to be fine. I also have DMA3 set to trigger from DMA1's 3-word block completion and perform a single word write from an SRAM array to DMA1's DMASA register. The Transfer size is configured so that once the array is exhausted, DMA3 will raise an event to toggle a GPIO, and I can see this is happening.
What I would expect to see is that the DMASA register of DMA1 is being changed - however whenever I halt the debugger I can see that the original programmed value is still there. DMA3 does not seem to be updating it. If I configure DMA3 to instead write to a value in SRAM, I can see that value is changing as expected. Is there something particular I need to do to ensure that the DMASA register is updated by a second DMA channel?
DMA1 is configured as this:
DMA3 is this:
And I'm using this code in my application:
static const uint32_t pulse_periods_and_length[NUM_PULSES * 3] = {LOAD_val0, 0, CC_01_val0, LOAD_val1, 0, CC_01_val1 ... }; static const uint32_t pulse_period_pointer[NUM_PULSES] = { (uint32_t)(&pulse_periods_and_length[0]), (uint32_t)(&pulse_periods_and_length[3]), ... (uint32_t)(&pulse_periods_and_length[24]), }; uint32_t test_array[NUM_PULSES] = { 0, }; int main(void) { SYSCFG_DL_init(); // configure initial period for timer DL_Timer_setLoadValue(DR_INST, DR1_START_PULSE_PERIOD_TICKS / 2); DL_Timer_setCaptureCompareValue(DR_INST, DR1_START_PULSE_HIGH_TIMER_VALUE, GPIO_DR_C0_IDX); DL_DMA_setSrcAddr(DMA, DR_PULSE_UPDATE_DMA_CHAN_ID, (uint32_t)(&pulse_periods_and_length[0])); DL_DMA_setDestAddr(DMA, DR_PULSE_UPDATE_DMA_CHAN_ID, (uint32_t)(&DR_INST->COUNTERREGS.LOAD)); DL_DMA_enableChannel(DMA, DR_PULSE_UPDATE_DMA_CHAN_ID); DL_DMA_setSrcAddr(DMA, DR_DMA_RECONFIGURE_CHAN_ID, (uint32_t)(&pulse_period_pointer[1])); DL_DMA_setDestAddr(DMA, DR_DMA_RECONFIGURE_CHAN_ID, (uint32_t)(&DMA->DMACHAN[DR_PULSE_UPDATE_DMA_CHAN_ID].DMASA)); // DL_DMA_setDestAddr(DMA, DR_DMA_RECONFIGURE_CHAN_ID, (uint32_t)(&test_array[0])); // DL_DMA_setTransferSize(DMA, DR_DMA_RECONFIGURE_CHAN_ID, 4); // shortened for testing DL_DMA_enableChannel(DMA, DR_DMA_RECONFIGURE_CHAN_ID); DL_Timer_startCounter(DR_INST); while(1) { __WFI(); } }
Hi Alan,
Generally, I don't think there are any special considerations that you need to make to write to the DMASA register using another DMA. I've done something similar (writing to DMACTL instead of DMASA) myself without doing anything unusual. I am wondering if the channel needs to be disabled to write to this register. Have you tried doing the same thing but disabling the channel before performing the transfer?
I could configure the channel as "block" instead of "repeat block", which would disable the channel after the end of the first transfer, as you suggest. If my DMA write to DMASA then worked as I'd hope, how would I re-enable the DMA channel?
When I wrote to the DMACTL register, I set the enable bit to re-enable. Would this work for your application? Let me know if you need further help with this.
In that scenario, I'd need a block write to write to both DMACTL and DMASA, and to be able to increment through a table of DMACTL/DMASA pairs - which I think would give me the same configuration issue that I'm facing with my first DMA channel.
I see. Well, to your original question, I believe the only thing that would prevent you from writing to that register is the channel being enabled.
Have you looked into whether the data table mode could solve your issue of needing to reconfigure the timer? I think that you would need 3 triggers to write 3 words of data, so this may not work for you depending on the needs of your application.
Thanks, table mode was a suggestion for the question that spawned this one (https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1290599/lp-mspm0g3507-configure-dma-block-mode-to-step-through-array-of-blocks). I've had a try to get it working, but I end up with the same ultimate problem - that I need to send new configuration to a timer block once per PWM pulse. Having briefly tried table mode, I can iterate through a table of registers after the first pulse, but when I get to the second pulse I need to be pointing to a different table and re-enabled.
I understand. I've been thinking about this for a bit and so far I am not aware of a way to do this. To rewrite the DMASA register I've only been able to do this by first disabling the DMA, and then you'll be stuck looping through the same clock configuration data. Maybe if you used a third dma channel set to perform single transfers to the second one to update the value sent to the clock config, and you left the value going to the DMACTL register the same (allowing you to do single transfers), and had the second dma complete signal trigger the third, this would be possible? It would be a mess but I think that would be possible. If you try this please let me know how it goes.