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.
Related
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);
}
I am trying to connect a PCF8574 I/O ex-pander to 89S51 MCU.
The device address as per data sheet is 27h and after adding write bit 0
the address is 4Eh and for read it is 4Fh. I am sending write request i.e.
4Eh and it somehow works. If i try to read by sending 4Fh then the ACK is
never received.
I have noticed that during the write request i can write any value that
does not have LSB 0. If any value with LSB 0 is sent for write then again
the chip doesnot send ACK.
From above i understood that LSB of the data or command that I am sending have
something to do with the ACK. If the LSB is 0 then the SDA line is set to
LOW by master. So the slave don't have to bring the SDA line low to send
back ACK. Does it mean that the slave is not sending the ACK at all. It is the
Master that is thinking falsely that ACK is available only because it has bring the
SDA line LOW and checking the same LOW and thinking its ACK from slave.
I may be mistaken, but in don't know how to get over this situation.
Below is my sample C code written in SDCC compiler. This is only the Write part.
Job of this code is to continuously send AAh and 55h to the slave so that is can
observe the port activity by connecting LED. It can send AAh but goes into infinite
loop while checking of ACK when tries to send 55h. Again here 55h have LSB 1 so it fails.**
#include<8052.h>
#define SDA P0_0
#define SCL P0_1
#define HEARTBEAT_LED P1_0
void msDelay(unsigned int);
void I2CStart(void);
void I2CStop(void);
void i2c_write_byte(unsigned char Data);
/*****************************************
* Write to slave device with
* slave address e.g. say 0x27+/W=0x4E
*****************************************/
void main(void)
{
I2CStart(); // Send start condition
i2c_write_byte(0x4E); // Send slave address + write request
while(1)
{
i2c_write_byte(0xAA); //Send data
msDelay(100);
i2c_write_byte(0xFF); //Send data
msDelay(100);
}
}
void I2CStart(void)
{
SDA = 1;
SCL = 1;
SDA = 0;
SCL = 0;
}
void I2CStop(void)
{
SDA = 0;
SCL = 1;
SDA = 1;
SCL = 0;
}
void i2c_write_byte(unsigned char Data)
{
unsigned char i;
for(i=0;i<8;i++)
{
SCL=0;
SDA=(Data &(0x80>>i));
SCL=1;
}
while(SDA!=0);
SCL=0;
SCL=1;
SCL=0;
}
void msDelay(unsigned int itime)
{
unsigned int i, j;
for(i=0;i<itime;i++)
for(j=0;j<127;j++);
}
I have compiled code to transmit data from an STM32 board to the Arduino Uno and print it on the serial terminal. I have previously written code, similar to this and it worked as expected.
However, when I try transmitting a string from the STM32 this time, the TX-Led of the Arduino blinks, which is strange.
I have checked the baud rate of both devices and they match. On the serial terminal of the Arduino, backward question marks are printed when I am transmitting a short string "Test".
Please could someone help me identify any potential problems with what I have done.
The code for the STM32 UART settings was generated by cubeMX:
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;`
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
The string and HAL_UART instruction to transmit the data:
char let[30] = "Test\r\n";
HAL_UART_Transmit(&huart1, (uint8_t*)let, strlen(let), 1000);
All necessary functions (MX_USART1_UART_Init()) have been called and the HAL_UART_Transmit() is in the while loop, situated in the main loop, as I have cross-checked that.
My arduino program:
void setup() {
Serial.begin(115200);
// Define the LED pin as Output
pinMode (13, OUTPUT);
Serial.println("Arduino UART Receiver");
Serial.println("-----------------------------");
}
void loop() {
digitalWrite(13, LOW);
//wait until something is received
while(! Serial.available());
digitalWrite(13, HIGH);
//read the data
char in_read=Serial.read();
//print the data
Serial.print(in_read);
}
Arduino Uno has only one USART hardware, and it's connected to a USART-USB converter chip. This bus is point-to-point and can't be shared by another device when there is an active connection between Arduino and PC.
The RX pin of the Arduino is driven by two devices: STM32 and the converter chip. Converter tries to keep that line at logic high (because the TX coming from the PC is idle) while STM32 tries to drive that line with its own TX. Anything can happen there... Arduino is probably getting junk from its RX line.
If you can somehow disconnect Arduino RX from the converter chip (cutting the trace for example) it will probably work. But then you won't be able to program Arduino again.
You may use a software serial pin instead of the hardware RX pin. I don't have much experience with Arduino but I'm sure there must be software serial libraries out there.
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.
I am using STM32F103C8 board and CubeMX to create the code. I have connected the M66 to STM32 to UART2 port. I try to send some commands to Quectel M66 via STM32's UART port. It receives the command but throws some junk characters. I have set the baud rate as 9600 for all UART ports. This is my code
void M66_Check()
{
char *buffer = "ATI\r\n";
char *rec_buffer = NULL;
rec_buffer = (char*)malloc(200 * sizeof(char));
if(HAL_UART_Transmit(&huart2,buffer,strlen(buffer),200) == HAL_OK)
{
printf("AT Command sent successfully\r\n");
HAL_Delay(1000);
}
else
{
printf("Not Sent\r\n");
}
HAL_UART_Receive(&huart2,rec_buffer,50,200);
printf("About to print Response from M66 \r\n");
HAL_Delay(2000);
printf(rec_buffer);
}
This is what I am getting...Result in Putty
Any help would be greatly appreciated
There is the only way - read the answer and parse it. Then you will know if the command was executed ok.
But your response shows that your UART is running another speed (9600) than the modem. If you have not changed anything it should be 115200 as it is default modem UART speed
I have found out the problem... I needed to transmit and receive in these formats....
I missed those (uint8_t *).
To Transmit -
HAL_UART_Transmit(&huart2, (uint8_t *)buffer, strlen(buffer), 100);
To Receive -
HAL_UART_Receive(&huart2, (uint8_t *)rec_buffer,50,2000);
Now there is no problem and I am getting the response correctly.
Thanks for your help...