how to read data from quectel L89 GPS module in stm32 using HAL_UART_Receive()? - stm32

I am using STM32F103C8T6 board and CubeMX to generate the code. I need to receive the GPS data from Quectel L89 module from UART2 port. when I try that I get some junk values only... I am using HAL_UART_Receive to receive data and print it in the putty console. Any help would be greatly appreciated.
This is my code.
void task1(void)
{
char *buffer = NULL;
buffer = (char*)malloc(400 * sizeof(char));
while(1)
{
HAL_UART_Receive(&huart2,buffer,350,500);
int size = strlen(buffer);
HAL_UART_Transmit(&huart1,buffer,size,500);
HAL_Delay(1000);
}
}
Image of the Result

try this
HAL_UART_Receive(&huart2,(uint8_t *)buffer,350,500);
and
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,size,500);
Because arguments needed for HAL functions are of uint8_t * type.

Related

How to work out 'read/write' function using the libmodbus?(c code)

I'm gonna to read/write under the modbus-tcp specification.
So, I'm trying to code the client and server in the linux environment.
(I would communicate with the windows program(as a client) using the modbus-tcp.)
but it doesn't work as I want, so I ask you here.
I'm testing the client code for linux as a client and the easymodbus as a server.
I used the libmodbus code.
I'd like to read coil(0x01) and write coil(0x05).
When the code is executed using the libmodbus, 'ff' is printed out from the Unit ID part.(according to the manual, 01 should be output for modbus-tcp.
I don't know why 'ff' is printed(photo attached).
Wrong result:
Expected result:
'[00] [00] .... [00]' ; Do you know where to control this part?
Do you have or do you know the sample code that implements the 'read/write' function using the libmodbus?
please let me know the information, if you know that.
ctx = modbus_new_tcp("192.168.0.99", 502);
modbus_set_debug(ctx, TRUE);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
tab_rq_bits = (uint8_t *) malloc(nb * sizeof(uint8_t));
memset(tab_rq_bits, 0, nb * sizeof(uint8_t));
tab_rp_bits = (uint8_t *) malloc(nb * sizeof(uint8_t));
memset(tab_rp_bits, 0, nb * sizeof(uint8_t));
nb_loop = nb_fail = 0;
/* WRITE BIT */
rc = modbus_write_bit(ctx, addr, tab_rq_bits[0]);
if (rc != 1) {
printf("ERROR modbus_write_bit (%d)\n", rc);
printf("Address = %d, value = %d\n", addr, tab_rq_bits[0]);
nb_fail++;
} else {
rc = modbus_read_bits(ctx, addr, 1, tab_rp_bits);
if (rc != 1 || tab_rq_bits[0] != tab_rp_bits[0]) {
printf("ERROR modbus_read_bits single (%d)\n", rc);
printf("address = %d\n", addr);
nb_fail++;
}
}
printf("Test: ");
if (nb_fail)
printf("%d FAILS\n", nb_fail);
else
printf("SUCCESS\n");
free(tab_rq_bits);
free(tab_rp_bits);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
That FF you see right before the Modbus function is actually correct. Quoting the Modbus Implementation Guide, page 23:
On TCP/IP, the MODBUS server is addressed using its IP address; therefore, the
MODBUS Unit Identifier is useless. The value 0xFF has to be used.
So libmodbus is just sticking to the Modbus specification. I'm assuming, then, that the problem is in easymodbus, which is apparently expecting you to use 0x01as the unit id in your queries.
I imagine you don't want to mess with easymodbus, so you can fix this problem pretty easily from libmodbus: just change the default unit id:
modbus_set_slave(ctx, 1);
You could also go with:
rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS);
ASSERT_TRUE(rc != -1, "Invalid broadcast address");
to make your client address all slaves within the network, if you have more than one.
You have more info and a short explanation of where this problem is coming from in the libmodbus man page for modbus_set_slave function.
For a very comprehensive example, you can check libmodbus unit tests
And regarding your question number 5, I don't know how to answer it, the zeros you mean are supposed to be the states (true or false) you want to write (or read) to the coils. For writing you can change them with the value field of function modbus_write_bit(ctx, address, value).
I'm very grateful for your reply.
I tested the read/write function using the 'unit-test-server/client' code you recommended.
I've reviewed the code, but there are still many things I don't know.
However, there is an address value that acts after testing each other with unit-test-server/client code and there is an address value that does not work
(Do you know why?).
-Checked and found that the UT_BITS_ADDRESS (address value) value operates from 0x130 to 0x150
-'error Illegal data address' occurs at values below -0x130 and above 0x150
-The address I want to read/write is 0x0001 to 0x0004(Do you know how to do?).
I want to know how to process and transmit data like the TX part of the right picture.
enter image description here
I'm running both client and server in my Linux environment and I'm doing read/write testing.
Among the wrong pictures...[06][FF]... <-- I want to know how to modify FF part (to change the value to 01 as shown in the picture)
enter image description here
and "modbus_set_slave" is the function for modbus rtu?
I'd like to communicate PC Program and Linux device in the end.
so Which part do I use that function?
I thanks for your concern again.

STM32F7 + FatFs = FR_NOT_READY

I am now using CubeMx 4.23.0 and FW package for STM32F7 1.8.0
MCU is STM32F746 on Core746i board.
Everything is generated by CubeMx automatically.
main.c:
SCB_EnableICache();
SCB_EnableDCache();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SDMMC1_SD_Init();
MX_USB_DEVICE_Init();
MX_FATFS_Init();
HAL_Delay(3000);
DebugString("start OK");
uint8_t res = 0;
FATFS SDFatFs;
FIL MyFile; /* File object */
char SD_Path[4];
res = f_mount(&SDFatFs, (TCHAR const*)SD_Path, 0);
sprintf(DebugStr, "f_mount = 0x%02X", res);
DebugString(DebugStr);
res = f_open(&MyFile, "test.txt", FA_READ);
sprintf(DebugStr, "f_open = 0x%02X", res);
DebugString(DebugStr);
sdmmc.c:
void MX_SDMMC1_SD_Init(void)
{
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 7;
//HAL_SD_Init(&hsd1);
// ^^^^^ I also tried this here
//HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B)
//^^^^ and this
}
In case of f_mount(&SDFatFs, (TCHAR const*)SD_Path, 0) <- with 1 here (forced mount), output is:
f_mount = 0x03
f_open = 0x01
With 0 (do not mount now) output is:
f_mount = 0x00
f_open = 0x03
0x03 value is FR_NOT_READY, but official info is pretty vague about it
Things I've tried:
Adding HAL_SD_Init(&hsd1) to MX_SDMMC1_SD_Init() since i didnt find where is SD card GPIO init happening.
2 GB noname SD card, 1 GB Transcend card.
Different hsd1.Init.ClockDiv 3 to 255.
Resoldering everything completely.
Switching to 4-bit wide bus using HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B);
Turn on and off pullups.
But card still does not mount. It's formatted in FAT, working on a PC, files i've tried to open are exist, but empty.
How to get it to mount?
Thanks in advance!
there was the problem with exact version of cubemx.
updating stm32cubemx helped.
You can try
`f_mount(0, "path", 0);
` after the f_open call . it may work.
If the function with forced mounting failed with FR_NOT_READY, it means that the filesystem object has been registered successfully but the
volume is currently not ready to work
. The volume mount process will be attempted on subsequent file/directroy function.
If implementation of the disk I/O layer lacks asynchronous media change detection, application program needs to perform f_mount function after each media change to force cleared the filesystem object.
Changing all SDIO pins except SDIO_CK to pull-up according to This Topic works for me
Try commenting MX_USB_DEVICE_Init(), see what happens.

stm32f4xx HAL lib & PCF8457AT - no response to write

I have stm32f4-discovery kit and I want to try i/o expander for hd44870 LCD . I have PCF8574AT link to io example like mine 8-bit expander where i2c address is 0x3f (checked by i2c scanner) on hi2c3 hardware. For c/c++ use HAL libraries on Eclipse environment. Ok take look at code.
First I initialize i2c3 - like Datasheet 100kHz on SCL:
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 100000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
Then try to send data to I/O expander. But before that I check that i/o is ready to use:
result = HAL_I2C_IsDeviceReady(&hi2c3,0x3f , 2, 2);
if (result == HAL_BUSY)
{
HD44780_Puts(6, 1, "busy");
}else{
HD44780_Puts(6, 1, "ready");
uint8_t data_io = 0xff;
HAL_I2C_Master_Transmit(&hi2c3, 0x3f, data_io, 1, 100);
}
On a same expander nothing changes. Any ideas what is wrong or maybe i/0 expander is broken ?
Im not sure about HAL driver, really never used HAL. But I have touched pcf8574 IO expander. As you said, you have checked it with scanner and if you get address, line and device is OK. As I am not expert on I2C and HAL libs,I'll show my I2C driver it relies on STM32 standard periphery drivers and it worked for PCF8574 and various I2C devices. There is an example,snippet(blocking mode, not irq based):
Checking if IO is not busy.
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_BUSY) == SET){
if((timeout--) == 0) return -ETIMEDOUT;
}
Generate start condition and set write condition(with address for write mode).
I2C_TransferHandling(&I2Cx, dev_addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TXIS) == RESET){
if((timeout--) == 0) return -ENODEV;
}
Now you can send data byte( it is your IO states), This function writes directly to I2C TX(transceiver) register :
I2C_SendData(&I2Cx, reg_addr);
while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TC) == RESET){
if((timeout--) == 0) return -EIO;
}
Generate reading condition and than read from PCF8574, data should be same as it was just written(if nothing toggles IO expander). Basically you can read byte or more bytes (depends on device). In your case PCF8574(8bit) gives only 1 byte.
I2C_TransferHandling(dev->channel,dev_addr, len, I2C_AutoEnd_Mode,I2C_Generate_Start_Read);
size_t i;
for(i=0;i<len;i++){
timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(dev->channel, I2C_ISR_RXNE) == RESET){
if((timeout--) == 0) return -EIO;
}
data[i] = I2C_ReceiveData(dev->channel);
}
You can continue RW operations, or just simply wait till device automatically stop transition on line:
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_STOPF) == RESET){
if((timeout--) == 0) return -EIO;
}
I2C_ClearFlag(&I2Cx, I2C_ICR_STOPCF);
This steps will write and read data. Anyway this chip has some tricky logic there, it more simplistic than it looks like.Actually it works just as simple OUTPUT. Extern input just triggers up PCF8574 pin and nothing more, no special configuration for input mode. For input monitor for sure use PCF8574 INT pin, PCF8574 will trigger INT pin.
For example:
If you want input pins, than just simply set pins to logic zero. And monitor INT pin,if change happens on input, INT pin will be triggered and you should read data via I2C .
For OUTPUT low just write zero's.
And for OUTPUT high set logic true.
You are using HAL so you have to read what happens inside HAL_I2C_Master_Transmit function. Do not forget that address is 7bit and first byte with address also includes R/W condition.First byte bit0 is R/W bit. So you should handle it.
for example with defines:
#define PCF8574_WRITE_ADRESS (0x40) /*for writing to chip*/
#define PCF8574_READ_ADRESS ((0x40)|0x01) /*for reading chip*/
Here is some links:
i2c explanations
this may help
Really nice guide!
Hope this will help to understand your problem and solve it.:)
thanks , Bulkin
I found obvious mistake . HAL libs do not i2c_address << 1 . I/YOU must put that in code not same result !
HAL_I2C_Master_Transmit(&hi2c3, (0x3f<<1), data_io, 1, 100);
or
$define i2c_address_write (0x3f <<1 )
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_write , data_io, 1, 100);
to read :
$define i2c_address_read ((0x3f <<1) | 0x01)
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_read , data_io, 1, 100);

(GSM module SM5100B + ATMEGA16A interface) Trouble sending SMS using AT commands in C code

I am having trouble with my university project for embedded systems. The goal is to establish an interface between a SM5100B GSM module and ATMEGA16A microcontroller, using UART (which I did, using the correct ports from the datasheets), and to be able to send/receive simple SMS messages by sending AT commands trough the Tx and Rx ports from atmega to gsm and vice versa, via C code in Atmel.(not using hyperterminal)
When I tested the GSM module using TeraTerm, i was able to connect properly, and send AT commands easily, also managed to send and recieve an SMS with the SIM card inserted, so everything works fine.
Now I'm trying to do that using the microcontroller.
Here is the code I have so far:
#define F_CPU 7372800UL
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/io.h>
#include <string.h>
#define BAUD 9600
#define MYUBRR ((F_CPU/16/BAUD)-1) //BAUD PRESCALAR (for Asynch. mode)
void GSM_init(unsigned int ubrr ) {
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
void USART_Transmit(char data ) {
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) );
/* Put data into buffer, sends the data */
UDR = data;
}
void USART_Transmits(char data[] ) {
int i;
for(i=0; i<strlen(data); i++) {
USART_Transmit(data[i]);
_delay_ms(300);
}
}
int main(void)
{
GSM_init(MYUBRR);
char text_mode[] = "AT+CMGF=1";
char send_sms[] = "AT+CMGS=";
char phone_number[] = "00385*********";
char sms[] = "gsm sadness";
USART_Transmits(text_mode);
_delay_ms(1000);
USART_Transmits(send_sms);
_delay_ms(1000);
USART_Transmit(34);//quotation mark "
//_delay_ms(300);
USART_Transmits(phone_number);
//_delay_ms(300);
USART_Transmit(34);//quotation mark "
//_delay_ms(300);
USART_Transmit(13);//enter
//_delay_ms(300);
USART_Transmits(sms);
_delay_ms(1000);
USART_Transmit(26);//ctrl+z
_delay_ms(300);
USART_Transmit(13);//enter
_delay_ms(3000);
while (1)
{
}
}
However, my code isn't working, it's not sending the message.
The functions for transmitting are taken from the datasheet and everywhere on the internet I search I find the same ones over and over again.
Is the problem in AT responses that I'm not reading correctly? Or in parsing AT commands to the serial port?
Can anybody help me understand where I'm going wrong with this, or where I can look for to understand how to make this work?

Extract frames from pcap files (tcpdump output) without using Libraries

I need to parse the pcap files and count the packets separately (TCP,UDP,IP). I found a lot of libraries for this like pcap, jnetpcap but I want to do this without using any external libraries.I do not need a code but a just a conceptual explanation.
Question
While parsing pcap files how should I distinguish between the frames(be it TCP,UDP,IP). I tried reading about the format but what I do not understand is how would I come to know about how many bytes should I read for a particular frame and how would i know what type of a frame is it.Because only once I am able to extract the packets separately I will be able to filter out other information.
You'd have to parse each frame separately and have a counter for each value you are trying to count. Assuming the capture you are examining is in pcap/pcapng format you might find libpcap helpful.
To give a quick run of what you might have to do (assuming the lower level is Ethernet without VLAN tags)
uint64_t ip_count, tcp_count, udp_count;
void parse_pkt(uint8_t *data, uint32_t data_len) {
uint8_t *ether_hdr = data;
uint16_t ether_type = ntohs(*(uint16_t *) (data + 12))
if (ether_type != 0x800) {
return;
}
ip_count += 1;
uint8_t *ip_hdr = data + 14;
protocol = ntohs(*(uint16_t *) (ip_hdr + 9))
//protocol is either udp/tcp/sctp...etc
if (protocol == 0x11) {
udp_count++;
} else if (protocol == 0x06) {
tcp_count++;
}
}
// foreach pkt from libpcap_open call parse_pkt with the data and data_len
This code is fragile. Jumping to direct offsets without the proper length and type checks is not a good idea.