DMA enabled ADC with FreeRTOS - stm32

With the DMA continuous requests, the program will just loop in DMA1_Channel1_IRQHandler and the FreeRTOS thread is not running.
Does anyone have any idea how to resolve this?
{
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_I2C2_Init();
MX_IWDG_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
uprintf("Before dma\n");
HAL_ADC_Start_DMA(&hadc1, adcBuffer, 2);
uprintf("After dma\n");
/* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

It sounds like your DMA channel has higher priority (NVIC priority) than the FreeRTOS task (NVIC priority) and is starving the scheduler. For troubleshooting, try setting your DMA channel to match FreeRTOS task setting (NVIC priority), or elevate the FreeRTOS to a higher priority than the DMA.
Setting the DMA to continuous requests probably is not the desired configuration for your application, or it just might be.

Related

STM32 F103 UART callback works only once

I'm using UART RX callback code from here https://www.programmersought.com/article/68737014549/
Looks like this non-blocking RX processing doesn't work in background as expected
/* USER CODE BEGIN USART1_Init 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer1, RXBUFFERSIZE); //This function will turn on the receive interrupt: flag bit UART_IT_RXNE, and set the receive buffer and the maximum amount of data received by the receive buffer */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
/* USER CODE END USART1_Init 2 */
I receive only once and can't process next incoming bytes, because RX buffer keeps only old value.
Is it something with example or HAL's issue?
HAL_UART_Receive_IT() arms the RX interrupt only once. This is the expected behavior. You need to call it again to re-arm the receiver, after you are done processing the receive buffer.
HAL_UART_Receive_IT() Called only once. If you want to receive data continuously after the call, you must call the function again
main()
.....
HAL_UART_Receive_IT(&huart2, &temp_rx, 1);
.....
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
// USART2 Rx Interrupt
if (huart->Instance == USART2) {
HAL_UART_Receive_IT(&huart2, &temp_rx, 1);
}

Having issues communicating STM32L443RCT with M95M02 EEPROM with SPI on FreeRTOS

I have two functions; EEPROM_SPI_WriteBuffer(TxBuffer, (uint32_t)0x00, (uint16_t)32); for writing a buffer data to a 24bit adress and EEPROM_SPI_ReadBuffer(RxBuffer, (uint32_t)0x00, (uint16_t)32); for reading that data from that adress.
My issue is that "write" function takes too long to complete if "read" function is called after that function.
Here is the RTOS task:
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
EEPROM_SPI_INIT(&hspi2);
EEPROM_SPI_WriteBuffer(TxBuffer, (uint32_t)0x00, (uint16_t)32);
osDelay(1000);
/* Infinite loop */
for(;;)
{
EEPROM_SPI_ReadBuffer(RxBuffer, (uint32_t)0x00, (uint16_t)32);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
osDelay(1000);
}
I can read the data if comment out the write function and write data if I comment out the read function everytime before I run the code.
I am using firebull's code Here
Anyone had any similar problems with this or could tell me where to look?

STM32 Flash Erase fails with a "Programming Parallelism error" and "Programming Sequence error"

I have an application running on an STM32F4 which uses the STM32 HAL framework + FreeRTOS. I occasionally need to store some settings in flash during runtime and have written the following function to erase the data at my target address of 0x08060000UL (I believe this is SECTOR_6 of this particular MCU).
HAL_StatusTypeDef Flash::erase(uint32_t address)
{
HAL_StatusTypeDef status;
HAL_FLASH_Unlock(); // unlock the flash API
__disable_irq(); // disable all interrupts
vTaskSuspendAll(); // suspend all FreeRTOS tasks
FLASH_EraseInitTypeDef eraseConfig = {0};
uint32_t sectorError;
uint32_t flashError = 0;
eraseConfig.TypeErase = FLASH_TYPEERASE_SECTORS;
eraseConfig.Sector = this->getSector(address);
eraseConfig.NbSectors = 1;
eraseConfig.VoltageRange = FLASH_VOLTAGE_RANGE_3;
status = HAL_FLASHEx_Erase(&eraseConfig, &sectorError); // <---- FAILS HERE
if (status != HAL_OK)
{
flashError = HAL_FLASH_GetError();
}
status = HAL_FLASH_Lock();
xTaskResumeAll(); // resume all FreeRTOS tasks
__enable_irq(); // re-enable interrupts
return status;
}
The flashError variable ends up getting set to 6, which means the following two errors occurred during the call to HAL_FLASHEx_Erase()
#define HAL_FLASH_ERROR_PGS 0x00000002U /*!< Programming Sequence error */
#define HAL_FLASH_ERROR_PGP 0x00000004U /*!< Programming Parallelism error */
I can't be 100% sure, but I think this code worked fine prior to implementing FreeRTOS. Regardless, what kind of behavior might cause such an error? I thought disabling all ISRs as well as suspending all tasks (even though there is only one running during this operation) would cover me, but no combination of these attempts alleviates the error 🤷‍♂️.
Turns out I had to reset some peripheral flags prior to using the HAL Flash API. Why? I don't know, but clearing all the flags prior to using the API fixed my problem.
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);

STM32 Uart Bridge

I am workin in a proyect where i need to make a bridge between to uart's. I am using the STM32F072CB Basically, all the data that I receive to the uart1 rx must be sent by uart2 tx. In the same way, what I receive in uart2 rx I must send through uart1 tx.(Both UARTs have the same baudrate). I am not aware of how much data I can receive on the rx uarts.
This is the idea
Uart1 rx --------> Uart2 tx
Uart1 tx <-------- Uart2 rx
I am using DMA with HAL_UARTEx_ReceiveToIdle_DMA to reduce cpu processing.
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart2_rx;
#define RXBuffSize 10
uint8_t RxBuff1[RxBuffSize];
uint8_t RxBuff2[RxBuffSize];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,RxBuff1,RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
HAL_UARTEx_ReceiveToIdle_DMA(&huart2,RxBuff2,RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
while (1)
{}
}
Here is my DMA interruption callback function
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART1)
{
HAL_UART_Transmit(&huart2,RxBuff1,RxBuffSize,1);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,RxBuff1,RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
}
else if (huart->Instance == USART2)
{
HAL_UART_Transmit(&huart1,RxBuff2,RxBuffSize,1);
HAL_UARTEx_ReceiveToIdle_DMA(&huart2,RxBuff2,RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
}
}
The code runs when the data input to rx is low. If I send too much data in the tx of the other uart I get the first bytes but lose the last ones. I also tried doing the RXBuffSize = 1 , that is to say receive a character and send it but I get the same result.
Because HAL_UART_Transmit operates in a "polling" method, it stops at the point until all strings are transmitted.
Therefore, if another string comes in while HAL_UART_Transmit is being executed, the interrupt is not executed and the entered string is lost.
After activating the TX DMA of each uart in cubemx, try applying the code as shown below.
#include <string.h>
uint8_t TxBuff1[RxBuffSize];
uint8_t TxBuff2[RxBuffSize];
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
Size = Size > RxBuffSize ? RxBuffSize : Size;
if (huart->Instance == USART1)
{
memcpy(TxBuff2, RxBuff1, Size);
HAL_UART_Transmit_DMA(&huart2, TxBuff2, Size);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RxBuff1, RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
}
else if (huart->Instance == USART2)
{
memcpy(TxBuff1, RxBuff2, Size);
HAL_UART_Transmit_DMA(&huart1, TxBuff1, Size);
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RxBuff2, RxBuffSize);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
}
}
Transmitting RxBuff directly is dangerous. When a character is received from the UART while sending, an incorrect value may be sent by the TX DMA because RX DMA changes the value in the corresponding memory.
Therefore, when RX DMA is deactivated, it is better to enable it after copying the corresponding memory value to another location.

I2C communication between two stm32 board in interrupt mode by low layer functions of STM32CUBEMX

I am working on a project which needs data communication between two stm32 (stm32f103rb and stm32f429zg).
I use stm32f103rb-nucleo examples_ll (I2C _OneBoard_Communication_IT) but it works for one byte and after that, it stops working. I want it to work repetitively.
the code structure is exactly in the way the example is written in the folder related to stm32cubemx repository.
I don't know how to make it work in a loop and by pressing the button, communication gets done every time I push the master and slave push buttons.
I have put the master completion callback function here :
void Master_Complete_Callback(void)
{
if(ubNbDataToReceive == 3)
{
/* Prepare the generation of a Non ACKnowledge condition after next received bytes */
LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);
/* Read character in Receive Data register.
RXNE flag is cleared by reading data in RXDR register */
aReceiveBuffer[ubReceiveIndex++] = LL_I2C_ReceiveData8(I2C1);
ubNbDataToReceive--;
/* Disable Buffer Interrupts */
LL_I2C_DisableIT_BUF(I2C1);
}
else if(ubNbDataToReceive == 2)
{
/* Generate Stop condition */
LL_I2C_GenerateStopCondition(I2C1);
/* Read character from Receive Data register.
RXNE flag is cleared by reading data in RXDR register */
aReceiveBuffer[ubReceiveIndex++] = LL_I2C_ReceiveData8(I2C1);
ubNbDataToReceive--;
/* Read character from shift register.
RXNE flag is cleared by reading data in RXDR register */
aReceiveBuffer[ubReceiveIndex++] = LL_I2C_ReceiveData8(I2C1);
ubNbDataToReceive--;
}
else
{
if(ubNbDataToReceive > 0)
{
/* Read character from shift register.
RXNE flag is cleared by reading data in RXDR register */
aReceiveBuffer[ubReceiveIndex++] = LL_I2C_ReceiveData8(I2C2);
/* Update ubNbDataToReceive variable */
ubNbDataToReceive--;
}
}
if(ubNbDataToReceive == 0)
{
/* (1) Disable I2C1 transfer event/error interrupts:
* - Disable Events Interrupt
* - Disable Error interrupts
*/
LL_I2C_DisableIT_EVT(I2C1);
LL_I2C_DisableIT_ERR(I2C1);
LL_I2C_EnableIT_EVT(I2C1);
LL_I2C_EnableIT_ERR(I2C1);
/* Read Received character.
RXNE flag is cleared by reading of RXDR register */
if(aReceiveBuffer[ubReceiveIndex-1] == SLAVE_BYTE_TO_SEND)
{
/* Turn LED2 On:
* - Expected byte has been received
* - Master Rx sequence completed successfully
*/
//LED_On();
HAL_UART_Transmit_IT(&huart2,(uint8_t*)"#Data transfer is OK!$",strlen("#Data transfer is OK!$"));
ubNbDataToTransmit = sizeof(SLAVE_BYTE_TO_SEND);
ubNbDataToReceive = sizeof(SLAVE_BYTE_TO_SEND);
}
else
{
/* Call Error function */
Error_Callback();
}
}
}
it is easily understood that the end of the transmission process is when I add HAL_UART function to send to serial port the transmission completion.
but after this time , it works one more time and after that it stops.
I have checked the oscilloscope signal show and after the second time transmission SCL pin gets LOW .
Thanks
Did not use LL for a long time, but isnt I2C interrupt disabled after single transfer with LL_I2C_DisableIT_EVT(I2C1);?? Make sure to enable it again before next transmission.
There is such a thing that two master devices cannot communicate each other via I2C bus. Because master devices do not have DEVICE_ADDRESS. Master devices can communicate only slave devices.