Passing a string variable from one file to another. STM32CubeIDE - c

this code is receiving either '1' or '0' through usb serial com port. If it is '1' then the LED turns on. If it is '0' the LED turns off. The following code works just fine if i use it in the file "usbd_cdc_if.c"....
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
if(Buf[0] == '1'){
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
}
else if(Buf[0] == '0'){
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
}
return (USBD_OK);
/* USER CODE END 6 */
}
But instead, i wanted to have the if statement in the "main.c" file rather than the "usbd_cdc_if.c" file. So both would look like this:
"usbd_cdc_if.c" file:
extern char serialCopy[];
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
memcpy(serialCopy,Buf,*Len);
return (USBD_OK);
/* USER CODE END 6 */
}
"main.c" file:
char serialCopy[MAX_LEN];
while (1)
{
if(strcmp(serialCopy, "1") == 0){
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
}
else if(strcmp(serialCopy, "0") == 0){
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}
}
When trying to copy the variable value from "usbd_cdc_if.c" to "main.c". The LED wouldnt work when i use my method. Why? Thanks

You changed the code. Buf[0] == '1' does not mean the same as strcmp(serialCopy, "1") == 0 since the latter assumes a null terminated string. Characters sent over serial buses are not null terminated unless you explicitly sent them as such.
Additionally, strings entered from a terminal on a PC are followed by a line feed character \n (*nix-like systems) or \r\n (Windows). Meaning that strcmp("1", "1\n"); will fail even if the string is correctly null terminated.
You should view the received data in the rx buffer using a debugger to see what you actually got.

Solved. The problem was that memcpy() in the usbd_cdc_if.c file is ony copying the data once but the loop in the main.c file keeps checking. Needed to use a global variable....
usbd_cdc_if.c file:
uint8_t newVariable = 0;
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
newVariable = Buf[0];
return (USBD_OK);
}
main.c file:
extern uint8_t newVariable;
while (1)
{
if(newVariable == '1'){
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
}
else if(newVariable == '0'){
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}
}
Now, it is working. I am not sure why all my tries didnt work.
Thank you.

Related

STM32 message filtering didn't work as expected

So, I'm trying to read my TESEO LIV3FL GNSS module using I2C communication and STM32 Nucleo-WL55JC1. I can print the sensor log to my serial monitor perfectly. Here's the screenshot
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGLL,0745.76471,S,11023.30874,E,040509.000,V,N*58
$PSTMCPU,27.96,-1,98*49
$GPRMC,040510.000,V,0745.76471,S,11023.30874,E,,,061222,,,N*62
$GPGGA,040510.000,0745.76471,S,11023.30874,E,0,00,99.0,175.23,M,0.0,M,,*7E
$GPVTG,,T,,M,,N,,K,N*2C
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGLL,0745.76471,S,11023.30874,E,040510.000,V,N*50
$PSTMCPU,15.14,-1,98*42
.76471,S,11023.30874,E,,,061222,,,N*6A
$GPGGA,040509.000,0745.76471,S,11023.30874,E,0,00,99.0,175.23,M,0.0,M,,*76
$GPVTG,,T,,M,,N,,K,N*2C
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGLL,0745.76471,S,11023.30874,E,040509.000,V,N*58
$PSTMCPU,27.96,-1,98*49
$GPRMC,040510.000,V,0745.76471,S,11023.30874,E,,,061222,,,N*62
$GPGGA,040510.000,0745.76471,S,11023.30874,E,0,00,99.0,175.23,M,0.0,M,,*7E
$GPVTG,,T,,M,,N,,K,N*2C
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGLL,0745.76471,S,11023.30874,E,040510.000,V,N*50
However, when I tried to filter only GPGGA message only it filtered the wrong message. Here's the serial monitor output
$GNGSA,A,1,,,,,,,,,,,,,9GPGGA,040509.000,0745.76471,S,11023.30874,E,0,00,99.0,175.0,99.0,99.0*1E6
$GNGSA,A,1,,,,,,,,,,,,,9GPGGA,040509.000,0745.76471,S,11023.30874,E,0,00,99.0,175.0,99.0,99.0*1E6
Where it should be
GPGGA,040509.000,0745.76471,S,11023.30874,E,0,00,99.0,175.0,99.0,99.0*1E6
GPGGA,040509.000,0745.76471,S,11023.30874,E,0,00,99.0,175.0,99.0,99.0*1E6
Here's my variable declaration
uint8_t receivedData[1000];
uint8_t filteredMessage[1000];
char buff[1000];
char *ptr;
const char desiredNMEA[] = "$GPGGA";
And my infinite loop
while (1)
{
// Start reading data
ret = HAL_I2C_IsDeviceReady(&hi2c1, TESEO_LIV3FL_ADDRESS, 2, 10);
if (ret != HAL_OK) {
sprintf((char*)buff, "Device is not ready \r\n");
} else {
ret = HAL_I2C_Master_Receive(&hi2c1, TESEO_LIV3FL_ADDRESS, receivedData, sizeof(receivedData), HAL_MAX_DELAY);
if (ret != HAL_OK) {
sprintf((char*)buff, "Error Rx \r\n");
}
}
ptr = strstr((char*)receivedData, desiredNMEA);
if(ptr) {
int position = ptr - (char*)receivedData;
while((char*)receivedData[position] != '\n') {
filteredMessage[position] = filteredMessage[position];
position++;
}
filteredMessage[position] = '\0';
HAL_UART_Transmit(&huart2, filteredMessage, strlen((char*)filteredMessage), HAL_MAX_DELAY);
HAL_Delay(500);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
Here's for the full code since it's too long. Any idea where did I go wrong?
Edit #1
When I unplugged and then plugged it again the data just become haywire
Edit #2
Implemented Flexz's solution. The data still corrupted and truncated but we're getting somewhere
⸮⸮榦x>ZGPGGA,055223.070,0745.75895,S,11GPGGA,055232.000,0745.75895,S,11GPGGA,055237.000,0745.75895,S,11023.30466,E,0,00,99.0,167.95,M,0.0,M,,*7C
'⸮⸮<⸮
⸮b⸮
Stm32 has nothing to do here, it's a bug in your code.
while((char*)receivedData[position] != '\n') {
filteredMessage[position] = filteredMessage[position];
position++;
}
Assigning the unassigned variable to itself? Of course it doesn't work.
And HAL_UART_Transmit is a blocking call, there is no reason to insert a delay after it.
The next problem is that you insert the part you want into the output buffer at the same position that it was at in the unfiltered buffer. You need to insert it into the output buffer starting at zero.

How to send a counter via UART

I have some problems with a program in which I want to send via UART a variable that is a counter.
The goal is to see this counter on Matlab Simulink.
Actually what I'm able to see on Matlab is not what i want to see, because I just see the values of the Characters in ASCII (I mean the characters of the printf...see the code then).
while(1){
HAL_UART_Receive_IT(&huart2, &bufferRX, 1);
//Serial Stream Routine
if(streamActive == 1 && counter < MAX_VALUE) //RUNNING state: we start the counter and the transmission begin
{
if (dataReady == 1)
{
printf("The actual counter value is: %d \r\n", counter);
counter++;
dataReady = 0;
}
}
else
if(streamActive == 1 && counter >= MAX_VALUE){
counter = 0;
}
So, if I want to transmit and visualize on simulink just the actual value of the counter, what I have to write here?
I also implemented these functions in order to use the UART:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart2, &bufferRX, 1);
}
And this is for the printf:
int __io_putchar(int ch)
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, sizeof(ch), HAL_MAX_DELAY);
/* Loop until the end of transmission */
while (HAL_UART_GetState(&huart2) == HAL_UART_STATE_RESET) {
}
return ch;
}

Is there a possibility to create a two way communication with uarts using HAL_UART_RxCpltCallback?

I am currently working on a project where i want to communicate with ESP8266 module using usart-1 and have another usart-2 which could be used in putty. My question is if there is any possibility to achieve this goal with HAL_UART_RxCpltCallback function? So far my all attempts to do so failed miserably and the best i could is creating communication where data can be send to esp but no answer can be captured. All my other attempts ended in creating a loop between usarts. Thank you in advance
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
uint8_t Data[50];
uint16_t size = 0;
size = sprintf(Data, "%c", Received);
if(Received != '\r' && Received != '\n')
{
RingBuffer_PutChar(&USART_RingBuffer_Tx, Received);
HAL_UART_Transmit_IT(&huart1, Data, size);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
else
{
if(Received == '\n')
{
//size = sprintf(Data, "\n\r", 2);
HAL_UART_Transmit_IT(&huart1,(uint8_t*) "\n\r", 2);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
if(Received == '\r')
{
if(!RingBuffer_IsEmpty(&USART_RingBuffer_Tx))
{
RingBuffer_PutChar(&USART_RingBuffer_Tx, '\r');
RingBuffer_PutChar(&USART_RingBuffer_Tx, '\n');
HAL_UART_Transmit_IT(&huart6, (uint8_t*) RingBufferData_Tx, sizeof(RingBufferData_Tx));
HAL_UART_Transmit_IT(&huart1, "\nSent\n\r", 12);
HAL_UART_Receive_IT(&huart6, &Received1, 1);
HAL_UART_Receive_IT(&huart1, &Received, 1);
RingBuffer_Clear(&USART_RingBuffer_Tx);
}
else
{
HAL_UART_Transmit_IT(&huart1,(uint8_t*) "Buffer is empty\n\r", 17);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
}
}
}
The HAL_UART_RxCpltCallback function has a parameter UART_HandleTypeDef *huart, so you can check which UART instance called this Callback.
You might check it whether it is usart-1 or usart-2 and execute the code according to this.

newlib printf function bug

I am trying to send printf data to my uart device.
I have suitablely written write_r() funciton.
The problems that I am having is,
When I say printf(" My name is sam \n I am fine ");
and in next time when i say printf(" I am back ");
1st problem : I can see only "My name is Sam", then the cursor goes to next line and stops there.
2nd problem : "I am back" is not getting printed at all.
I tried by removing \n , still the 2nd printf doesn't get printed.
There is nothing wrong with the uart.
Looks like then \ is reached the pointer is lost.
My Code
int write(int file, char *ptr, int len) {
#if !defined( OUT_8 )
#define OUT_8(p,d) (*(volatile char *)(p) = (char)(d))
#endif
#if !defined( IN_8 )
#define IN_8(p) ((*(volatile char *)(p)))
#endif
OUT_8(DUART1_UMCR1, 0x02); //Informs external modem or peripheral that the UART is ready for sending data
OUT_8(DUART1_ULCR1, 0x03);
OUT_8(DUART1_UIER1, 0x0f);
OUT_8(DUART1_UFCR1, 0x8f);
OUT_8(DUART1_UTHR, '\n');
OUT_8(DUART1_UTHR, '\r');
while (ptr!=NULL)
{
if (*ptr=='\n') // JUST A TRY to avoid \n bug
{
OUT_8(DUART1_UTHR, '\n');
wait();
*ptr++;
*ptr++;
OUT_8(DUART1_UTHR, *ptr++); // \n & \r when given through printf isNot working
wait();
}
OUT_8(DUART1_UTHR, *ptr++); // \n & \r when given through printf is not working
wait(); // TODO:
if(len==0)
break;
else
len--;
}
OUT_8(DUART1_UMCR1, 0x00); // say that modem is not not ready. Connection over
OUT_8(DUART1_UFCR1, 0x87);
OUT_8(DUART1_ULCR1, 0x00); // Clear all the interrupts ! virtually shut the UART port
errno = ENOSYS;
return -1;
}
Confident that OP's I/O is buffered somewhere.
Output does not appear until a \r and/or \n is sent.
#if !defined( OUT_8 )
#define OUT_8(p,d) (*(volatile char *)(p) = (char)(d))
#endif
// make ptr a `const char *`
int write(int file, const char *ptr, int len) {
OUT_8(DUART1_UMCR1, 0x02); //Informs UART is ready for sending data
OUT_8(DUART1_ULCR1, 0x03);
OUT_8(DUART1_UIER1, 0x0f);
OUT_8(DUART1_UFCR1, 0x8f);
while (len-- > 0) {
OUT_8(DUART1_UTHR, *ptr++);
wait();
}
// Force an EOL at the _end_ of transmission.
OUT_8(DUART1_UTHR, '\n');
OUT_8(DUART1_UTHR, '\r');
wait();
OUT_8(DUART1_UMCR1, 0x00); // say that modem is not not ready. Connection over
OUT_8(DUART1_UFCR1, 0x87);
OUT_8(DUART1_ULCR1, 0x00); // Clear all interrupts! virtually shut UART port
errno = ENOSYS;
return -1;
}
I suspect that the buffering is occurring in the receiving side, either the UART or more likely in the terminal viewing the data. OP said "the curser goes to next line". There is no "cursor" in a UART.
Try calling fflush() to force printing without a \n.

Weird thing in file-descrpiter I/O for gpio port

I'm coding in Linux to control the gpio port on my board, using the following codes. However,the result from read() is always a 0x10, which is a hex for LF line feed.
Voltage is an enum variable having int value of 0 and 1 standing for low and high. fd is the file descripter for the gpio port. 0x30 is hex code for char '0'. There is no error in write().
int set_gpio( int fd,enum voltage_e voltage)
{
const unsigned char w_buff =0x30+voltage;
unsigned char r_buff='2';
if (0 >= write(fd, &w_buff, 1))
{
LOGD(" Error1 in setting gpio to %d", voltage);
return -1;
}
__usr_sleep(0, 10000000);
if (read(fd, &r_buff, 1))
{
if (r_buff != 0x30+voltage)
{
LOGD(" r_buff is %d", r_buff);
return -1;
}
}
else
{
LOGD(" Error3 in setting gpio to %d", voltage);
return -1;
}
return 0;
}
For compatibility with shell utilities, the content of a GPIO port is typically a single character followed by a newline -- for instance:
% xxd /sys/class/gpio/gpio89/value
0000000: 310a 1.
Writing a single character to the GPIO device is advancing the file pointer to the second character, which is always the newline which you're seeing.
You will need to reset the file pointer to the beginning before doing a read/write operation:
lseek(fd, 0, SEEK_SET);

Resources