Using DMA with two UART peripherals - is it possible? - stm32

I want to connect two UART peripherals using STM32G0 microcontroller via DMA. Not knowing the length of the messages in forward, I'm using function HAL_UARTEx_ReceiveToIdle_DMA() in order to receive them. Here is the part of my code:
main.h
.
.
.
StartDMAReceptionOverUART1();
StartDMAReceptionOverUART4();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(10);
}
.
.
.
void StartDMAReceptionOverUART1(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_modulePort.huart, m_modulePort.rxBuffer, m_modulePort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_TC);
}
void StartDMAReceptionOverUART4(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_meterPort.huart, m_meterPort.rxBuffer, m_meterPort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_TC);
}
.
.
.
These functions are similar: first HAL_UARTEx_ReceiveToIdle_DMA() is checked, then Half Transfer and Transfer Complete interrupts are disabled in order to relieve processor (I need only IDLE interrupt). The problem is inside StartDMAReceptionOverUART1() function, HAL_UARTEx_ReceiveToIdle_DMA() never returns HAL_OK and program jumps on Error_Handler(). On the other hand, StartDMAReceptionOverUART4() works perfectly fine. What could be the problem?
Also, here is the receive callback function, also written inside main.h:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == m_meterPort.huart->Instance) // huart == UART4
{
memcpy(m_modulePort.txBuffer, m_meterPort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_modulePort.huart, m_modulePort.txBuffer, Size);
StartDMAReceptionOverUART4();
}
else if (huart->Instance == m_modulePort.huart->Instance) // huart == UART1
{
memcpy(m_meterPort.txBuffer, m_modulePort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_meterPort.huart, m_meterPort.txBuffer, Size);
}
else
{
return;
}
}
Callback function, in dependence of the periphery, will copy received data to a buffer and send it to the other periphery (functions memcpy() and HAL_UART_Transmit_DMA()). DMA over UART4 is in Normal mode, therefore StartDMAReceptionOverUART4() is called, inside which is HAL_UARTEx_ReceiveToIdle_DMA(). On the other hand, DMA over UART1 is in Circular mode, so there is no need for calling StartDMAReceptionOverUART4().

Related

STM32 HAL I2C Slave Interrupts Stop Working

I'm working with an STM32 (STM32F030K6TX) with the HAL Library. The STM32 functions as a slave device, all events are triggered by interrupts by events from the master MCU (Jetson Nano), interrupting the main loop running on the STM32. Upon resetting the device, the I2C works for a period of time, fulfilling several I2C requests before it stops working. When this happens the interrupts stop firing on the STM32 and all I2C reads/writes from the master MCU time out. The main loop is still active.
I noticed the HAL_I2C_GetError(&hi2c1) = HAL_I2C_ERROR_AF after these events. I tried to see if I could disable and re-enable the I2C to fix the interrupts, but it does not work. The code restores the state of the I2C to listening and clears the errors, but the interrupts still do not fire.
Does anyone know what might be the cause of these errors, and/or logic that can restore the I2C to a good state if this occurs?
MX_DMA_Init();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_DMA_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
transferState = 0;
while (1)
{
// 2) Respond to I2C Requests
if (transferState == 1) {
transferState = 2;
if (transferDirection == I2C_DIRECTION_TRANSMIT) {
// Receive a message from the Jetson, it's telling us to do something!
HAL_StatusTypeDef receiveState = HAL_I2C_Slave_Seq_Receive_DMA(&hi2c1, (uint8_t *)jetsonRequestRX, RXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME);
if(receiveState != HAL_OK)
{
Error_Handler();
}
} else {
// State is listen. This request fails... why?
if(HAL_I2C_Slave_Seq_Transmit_DMA(&hi2c1, (uint8_t *)jetsonTransmitPos, TXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME) != HAL_OK)
{
Error_Handler();
}
reset_calibration();
}
}
// This code attempts to detect the error condition and fix the I2C interrupts, but does not work
else if (transferState == 0) {
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
HAL_I2C_DeInit(&hi2c1);
HAL_I2C_Init(&hi2c1);
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
}
}
// *** ... Main loop ...
}
/* USER CODE BEGIN 4 */
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
transferState = 0;
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
jetsonRequest[0] = jetsonRequestRX[0];
jetsonRequest[1] = jetsonRequestRX[1];
transferState = 0;
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* restart listening for master requests */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
UNUSED(AddrMatchCode);
if(transferState == 0) {
transferState = 1;
transferDirection = TransferDirection;
}
}
the slave and listen hal is not very robust nor simple to use
i had use it very rarely and with hard time always
i remenber the hal handle do have some internal state or alike that went wrong in rare or unexpected error or if you rd/Wr less data than initaly expected or you don't do "right" (wjat they expect you) on the callback.
In this case it wan't restart operating correctly until state it's not hacked.
Try hanlding all hal error callback to see if their'ss any error thrown before it get screwd.
I don't have the f/W working in slave mode right now with me to help more :/

Does HAL_NVIC_SetPendingIRQ call the ISR to execute?

I am really new to STM32 world so I came across this while reading:
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);
This will cause the interrupt to fire, as it would be generated by the hardware. A distinctive feature
of Cortex-M processors it that it is possible to programmatically fire an interrupt inside the ISR
routine of another interrupt.
I got this from the book Mastering STM32 (by Carmine Noviello page 208). From this I have understood that If we set this pending bit even from the main function, then the interrupt is generated.
So to try this out, I have written this code:
while (1)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
for(int i = 0; i <10000000; i++);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
for(int i = 0; i <10000000; i++);
HAL_NVIC_SetPendingIRQ(EXTI0_IRQn);
}
}
along with this call back function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN){
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
I have programmed GPIO_PIN_0 as source of interrupt and when I press the push button connected to PA0 the Interrupt works perfectly i.e. ISR is executed. To my surprice HAL_NVIC_SetPendingIRQ function doesn't generate interrupt. I don't understand why?
More Info:
I am using STM32F411VET6 DISCO board
I am using STM32CubeIDE to program the board
Thank you #Tagli. I have found the function HAL_GPIO_EXTI_IRQHandler inside stm32f4xx_hal_gpio.c file. Defalult definition was like this:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
I got why the GPIO was not being toggled. It was the same reason you have commented above.
I have modified to prove it.
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
HAL_GPIO_EXTI_Callback(GPIO_Pin);
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
Now the callback function is called when the HAL_NVIC_SetPendingIRQ(EXTI0_IRQn); is being called

STM32 UART : HAL_UART_Transmit_IT Not working with Task

My UART tx Working with blocking mode and before FreeRtoss kernel start. But if I try to transmit inside task Not working( see below code ). Is any special code needed ?
enter code here
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_UART_Transmit_IT(&huart2, hi, sizeof(hi));
osDelay(1000);
}
/* USER CODE END 5 */
}

STM32F407 UART Communication

I am trying to set up a communication between my STM32F4 - Discovery with Open 407V-D development board and a peripheral using UART3 as a RS-485 bus.
I have problem with my communication becouse Rx state of UART remain busy.
Could somebody please explain me what am I doing wrong?
Should I somehow edit HAL_UART_IRQHandler or what setting am I missing?
Here is my code:
#include "main.h"
#include "stm32f4xx_hal.h"
UART_HandleTypeDef huart3;
uint8_t Ocular_1_RxBuffer[4];
uint8_t Ocular_1_TxBuffer[2] = {0x01,0x86};
__IO ITStatus UartReady;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART3_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); //set RS 485 into transmit mode
while (1)
{
int Timeout = 1000000;
while(huart3.gState != HAL_UART_STATE_READY) //wait for UART
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
Timeout = 1000000;
if(HAL_UART_Transmit_IT(&huart3, (uint8_t*)Ocular_1_TxBuffer, 2) != HAL_OK) //Send request
{
Error_Handler();
}
while(huart3.RxState != HAL_UART_STATE_READY) //wait for UART
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
Timeout = 1000000;
if(HAL_UART_Receive_IT(&huart3, (uint8_t*)Ocular_1_RxBuffer, 4) != HAL_OK) //Response
{
Error_Handler();
}
while(UartReady == RESET) //Wait for response
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
}
}
I have successfully received response from my peripheral device, but my code generate Error_Handler() after HAL_UART_RxCpltCallback() function.
Could somebody please explain this behavior to me?
My callback functions:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{
/* Set transmission flag: transfer complete */
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
UartReady = RESET;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
/* Set transmission flag: transfer complete */
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
UartReady = SET;
}
Please mention the number of bytes you are receiving in current scenario.?
Some debugging tips are -
Try increasing the size of your buffer and check if you are receiving any data.
Make sure you are re initialising your buffer after 4 bytes are read. If not the buffer can overflow and may lead to error handler.
Make sure you transmitter always sends 4 bytes.
Confirm if your buad rate matches on both devices. Also settings like parity and all are same in receiver and transmitter.
After every 4 bytes you need to call the HAL_UART_Receive_IT() again to configure and wait for next interrupt.
Add Error callback too, and confirm if execution moves to this callback. If then add prints in driver to find out whats the error cause, whether its like overrun error / Noise error / Parity Error etc.

CubeMX - I2C DMA - help needed - ST32F1

HAL_I2C_Mem_Write_DMA / HAL_I2C_Mem_Read_DMA what is the problem ?
Hi I'm trying to run I2C in DMA mode with LIS35 (accelerometer). I wrote simple code as below but each time when I try to run or debug it I'm getting back return "LIS35_ERROR;" which means that LIS35_I2C_Init(void) function goes wrong.
Previously (I mean yesterday) I wrote two similarly projects:
First was based on HAL_I2C_Mem_Write / HAL_I2C_Mem_Read functions
- and all works properly (return LIS35_OK;)
Second was based on HAL_I2C_Mem_Write_IT / HAL_I2C_Mem_Read_IT functions
- and all works properly(return LIS35_OK;)
Environment:
STM32CubeMX - updated today,
Board - Nucleo-F103RB
CubeMX project added as attachment
I2C configuration al on pictures below
/* USER CODE BEGIN 4 */
char LIS35_I2C_Init(void)
{
uint8_t Sett_Lis35_cr2_boot = LIS35_REG_CR2_BOOT;
uint8_t RegVal, LIS35Settings;
HAL_StatusTypeDef state1, state2, state3;
volatile long int i;
//reset LIS35 settings
if(HAL_I2C_Mem_Write_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR2, 1, &Sett_Lis35_cr2_boot, 1) != HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
//Write settings - activate all axis
LIS35Settings = LIS35_REG_CR1_XEN | LIS35_REG_CR1_YEN | LIS35_REG_CR1_ZEN | LIS35_REG_CR1_ACTIVE;
//WRITE CONFIGURATION TO LIS35 CHIP
if(HAL_I2C_Mem_Write_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR1, 1, &LIS35Settings, 1)!= HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
//Read configuration - if OK, LIS35 is up and running
if(HAL_I2C_Mem_Read_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR1, 1, &RegVal, 1) != HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
if (RegVal == LIS35Settings){
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
return LIS35_OK;
}
return LIS35_ERROR;
}
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c){
static uint8_t cntTx;
cntTx++;
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c){
static uint8_t cntRx;
cntRx++;
}
/* USER CODE END 4 */
Thanks in advance for any help :-)
Farnk