Cause for writing this question:
I think I found a bug. This happens when I try to enable DMA for SDADC and Input Capture.
Introduction:
I'm using STM32F373VBTx processor and it working great! Except when I try to enable DMA for TIM16 and TIM17 as Input Capture and SDADC1, SDADC2 and SDADC3. What happens is that the values from these peripherals only call DMA request 1 time and never more.
Method - Input Capture:
I enable IC1 (Input Capture 1)
I enable IC0 (Input Capture 0)
Then I start IC with DMA.
volatile static uint16_t input_capture0[2] = {0};
volatile static uint16_t input_capture1[2] = {0};
void STM32_PLC_Start_Input_Capture(TIM_HandleTypeDef* htim17, TIM_HandleTypeDef* htim16) {
/*
* Input capture for measuring frequency
* For TIM17 and TIM16
* Timer clock: 48 Mhz
* Prescaler: 4799
* Counter: 65535 (0xffff)
* Update frequency: 0.1526 Hz (1/0.1526 = 6.5535 seconds)
* Example: For every second, it will count 10000
* Lowest frequency measurement: 1/(0xFFFF*0.0001) = 0.1526 Hz
* Highest frequency measurement: 1/(1*0.0001) = 10000 Hz
*/
if(HAL_TIM_IC_Start_DMA(htim16, TIM_CHANNEL_1, (uint32_t*)input_capture1, 2) != HAL_OK)
Error_Handler();
if(HAL_TIM_IC_Start_DMA(htim17, TIM_CHANNEL_1, (uint32_t*)input_capture0, 2) != HAL_OK)
Error_Handler();
}
Method - Sigma Delta ADC
I enable Sigma Delta ADC 1
Sigma Delta ADC 2
Sigma Delta ADC 3
And for timer 12 and timer 13
Results - Input Capture
When I call to read the arrays input_capture0, input_capture1
then the DMA has only filled the arrays 1 time only. Only the first element has a value, the rest of the elements has 0 value. I try to pulse 3.3V onto the Input Capture pin, but it only react once.
static float compute_frequency(uint16_t input_capture[]) {
/*
* Typical worst case scenarios:
* T1: 0xFFFF - T0: 0x0
* T1: 0x0 - T0: 0xFFFF
* T1: 0x7FFF - T0: 0x7FFF
* T1: 0x0 - T0: 0x0
*/
uint16_t difference;
if(input_capture[1] > input_capture[0]) {
difference = input_capture[1] - input_capture[0];
return (float) 1/(difference*0.0001f);
} else if(input_capture[1] < input_capture[0]) {
difference = 0xFFFF - input_capture[1] + input_capture[0] + 1;
return (float) 1/(difference*0.0001f);
} else {
return 1/(65335*0.0001f);
}
}
float STM32_PLC_Input_Capture_Get(uint8_t i) {
if(i == 0)
return compute_frequency((uint16_t*)input_capture0);
else
return compute_frequency((uint16_t*)input_capture1);
}
Result - Sigma Delta ADC
When I try to read the arrays SDADC1_Single, SDADC2_Single, SDADC3_Differential
, only the first element has a value, the rest of the elements has 0 values.
/* Get raw ADC0 to ADC11 */
uint16_t STM32_PLC_Analog_Input_ADC_Get_Raw(uint8_t i) {
if(i < 9)
return SDADC1_Single[i] + 0x8000;
else
return SDADC2_Single[i-9] + 0x8000;
}
/* Get raw DADC0 to DADC4 */
int16_t STM32_PLC_Analog_Input_DADC_Get_Raw(uint8_t i) {
return SDADC3_Differential[i];
}
Discussion:
If I enable change Circular Mode to
Normal Mode
It will give me the same results. The first element get a value, the rest of the elements are zero.
Question:
What do you think causing this issue? Why does not the whole array completes?
Here is my main.c configuration file.
Update 1:
I tried to change the gain and offset at SDADC1 and this is how it goes. To change the gain, you need to call
HAL_StatusTypeDef HAL_SDADC_InjectedStop_DMA(SDADC_HandleTypeDef *hsdadc)
{
HAL_StatusTypeDef status;
/* Check parameters */
assert_param(IS_SDADC_ALL_INSTANCE(hsdadc->Instance));
/* Check SDADC state */
if((hsdadc->State != HAL_SDADC_STATE_INJ) && \
(hsdadc->State != HAL_SDADC_STATE_REG_INJ))
{
/* Return error status */
status = HAL_ERROR;
}
else
{
/* Clear JDMAEN bit in SDADC_CR1 register */
hsdadc->Instance->CR1 &= ~(SDADC_CR1_JDMAEN);
/* Stop current DMA transfer */
if(HAL_DMA_Abort(hsdadc->hdma) != HAL_OK)
{
/* Set SDADC in error state */
hsdadc->State = HAL_SDADC_STATE_ERROR;
status = HAL_ERROR;
}
else
{
/* Stop injected conversion */
status = SDADC_InjConvStop(hsdadc);
}
}
/* Return function status */
return status;
}
Then it will call this function to abort DMA.
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
if(hdma->State != HAL_DMA_STATE_BUSY)
{
/* no transfer ongoing */
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
else
{
/* Disable DMA IT */
hdma->Instance->CCR &= ~(DMA_IT_TC | DMA_IT_HT | DMA_IT_TE);
/* Disable the channel */
hdma->Instance->CCR &= ~DMA_CCR_EN;
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_FLAG_GL1 << hdma->ChannelIndex);
}
/* Change the DMA state*/
hdma->State = HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return HAL_OK;
}
Here we can clearly see that the DMA wasn't started, even if I got values from DMA once.
Update 2:
Here is the complete project. Import it with STM32CubeIDE.