DMA multibuffer current target and NDTR
Hey everyone,
I've got a weird issue.
I'm running a multibuffer DMA and although everything works well at a point, I'm terminating the DMA transfer.
It's a multibuffer DMA moving data from GPIO IDR to SRAM.
When an interrupt is triggered, I should stop the transfer, look at what the current memory target of the DMA is and move the remaining data to an sdcard (as indicated by the NDTR register)
Here's the code:
void EXTI3_IRQHandler(void) {
//Deactivate ADC
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_15, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4 | GPIO_PIN_5, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
//Stop DMA transfer
__HAL_TIM_DISABLE_DMA(&htim8, TIM_DMA_CC2|TIM_DMA_CC3);
__HAL_TIM_DISABLE_IT(&htim8, TIM_DMA_CC2|TIM_DMA_CC3);
volatile int datatowrite;
//Determine current memory target
if (((hdma_tim8_ch1_ch2_ch3.Instance->CR) && 262144) == 0) {
//memory target 0 -> determine amount of data left
datatowrite = 16200 - (hdma_tim8_ch1_ch2_ch3.Instance->NDTR - 16200);
res5 = f_write(&SDFile, &aDST_Buffer1[0], datatowrite, &wbytes);
} else {
//memory target 1 -> determine amount of data left
datatowrite = 16200 - (hdma_tim8_ch1_ch2_ch3.Instance->NDTR);
res5 = f_write(&SDFile, &aDST_Buffer2[0], datatowrite, &wbytes);
}
//close, unmount and deactivate SD peripheral
res7 = f_close(&SDFile);
f_mount(0, "", 0);
HAL_SD_MspDeInit(&hsd1);
//activate bleed resistor
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
__disable_irq();
__enable_irq();
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
//clear buffers
memset(&aDST_Buffer1, 0, sizeof(aDST_Buffer1));
memset(&aDST_Buffer2, 0, sizeof(aDST_Buffer2));
//deactivate stream and reset NDTR
hdma_tim8_ch1_ch2_ch3.Instance->CR ^= 1UL << 0;
hdma_tim8_ch1_ch2_ch3.Instance->CR &= ~(1UL << 19);
hdma_tim8_ch1_ch2_ch3.Instance->NDTR = 0x7e90;
hdma_tim8_ch1_ch2_ch3.Instance->CR ^= 1UL << 0;
deepsleep();
}So the comments should help Identify what I'm doing at each portion, the weird part comes in with the CT and NDTR registers. The CT is always correct, if its memory pointer 1, I can correctly see it in the register and the correct buffer is chosen. The problem is with the NDTR register.
The NDTR register starts off with a value of 32400 (each buffer is 16200), although when memory pointer 1 is selected in the CT register, there are points where the NDTR register has a value of say 17000, which means it is still servicing CT = 0. Looking at the data buffers, it is clear that it is busy with the memory zone CT=1 and not CT=0. this results in an overflow for me, as for memory pointer one the remaining data to write I calculate as :
datatowrite = 16200 - (hdma_tim8_ch1_ch2_ch3.Instance->NDTR);
datatowrite = 16200 - (hdma_tim8_ch1_ch2_ch3.Instance->NDTR);So when it is busy with the second memory region, the NDTR register should be <=16200, for instance if NDTR = 15000, I know that it has written 16200 - 15000 into the buffer and therefore the buffer has 1200 items. Although the NDTR sometimes shows >16200 and when I do the subtraction, I get an overflow. It doesn't seem to correspond correctly to the value when I look at the amount that the buffer is filled.
I'm very confused by this and not sure if I'm doing something wrong in the code. Any help will really be appreciated!
