debevv / nanoMODBUS

A compact MODBUS RTU/TCP C library for embedded/microcontrollers
MIT License
282 stars 58 forks source link

Hardfault in library (Guessing Memory address fault) #47

Open greenscreenflicker opened 5 months ago

greenscreenflicker commented 5 months ago

I'm porting nanoMODBUS to a microcontroller (CH32V003).

I have the issue that i get a hardfault To diaganose that error i wrote a fake_data function, that simulates a coil read, that gives always the same data. char fakedata[8]={0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x3D, 0xCC}; In the hardfault interrupt, i look where the hardfault happened by using a global variable. It takes several iterations until this happens, it doesn't happen strait away.

The code is based on the arduino slave example, but the error seems to be inside the library.

What do i see? grafik It crashes inside the routine (_hardfault_was_inside_readwrite==1) and it has always 2 chars left in the buffer. (mb_recievebuffer_index=2) So i gues it's before the checksum is there.

@debevv can you please help to investigate?

`

include "unified.h"

/* This example application sets up an RTU server and handles modbus requests

This server supports the following function codes: FC 01 (0x01) Read Coils FC 03 (0x03) Read Holding Registers FC 15 (0x0F) Write Multiple Coils FC 16 (0x10) Write Multiple registers */

nmbs_t nmbs;

// The data model of this sever will support coils addresses 0 to 100 and registers addresses from 0 to 32

define COILS_ADDR_MAX 64

define REGS_ADDR_MAX 32

// Our RTU address

define RTU_SERVER_ADDRESS 1

// A single nmbs_bitfield variable can keep 2000 coils nmbs_bitfield server_coils = {0}; uint16_t server_registers[REGS_ADDR_MAX] = {0};

define MB_RECIEVEBUFFER_SIZE 100

uint8_t mb_recievebuffer[MB_RECIEVEBUFFER_SIZE]; uint32_t mb_recievebuffer_index=0;

void delay1msec(void){ uint32_t countdown=8000; while(countdown--) asm(""); }

uint8_t _hardfault_was_inside_readwrite=0;

void fake_data(uint8_t* buf,uint16_t count){ _hardfault_was_inside_readwrite=5; if((mb_recievebuffer_index+count)<=MB_RECIEVEBUFFER_SIZE){ memcpy(&mb_recievebuffer[mb_recievebuffer_index],buf,count); mb_recievebuffer_index+=count; } _hardfault_was_inside_readwrite=1; }

int32_t read_serial(uint8_t buf, uint16_t count, int32_t byte_timeout_ms, void arg) { _hardfault_was_inside_readwrite=2; while(byte_timeout_ms--){ // uint32_t recbytes=mcu_tracer_usart_recieved_bytes(); // if(recbytes>0){ // //copies the number of recieved bytes // uint32_t datalen; // uint8_t *data; // data=mcu_tracer_rx_pingpong_buf(&datalen); // if((mb_recievebuffer_index+datalen)>=MB_RECIEVEBUFFER_SIZE){ // datalen=MB_RECIEVEBUFFER_SIZE-mb_recievebuffer_index; // } // memcpy(&mb_recievebuffer[mb_recievebuffer_index],data,datalen); // mb_recievebuffer_index+=datalen; // } if(count<=mb_recievebuffer_index){ _hardfault_was_inside_readwrite=3; memcpy(buf,&mb_recievebuffer[0],count); mb_recievebuffer_index=mb_recievebuffer_index-count; if(mb_recievebuffer_index>0){ _hardfault_was_inside_readwrite=4; memmove(&mb_recievebuffer[0],&mb_recievebuffer[count],mb_recievebuffer_index); } _hardfault_was_inside_readwrite=1; return count; }

// delay1msec(); // byte_timeout_ms--; // if(byte_timeout_ms<1){ // memcpy(buf,&mb_recievebuffer[0],mb_recievebuffer_index); // mb_recievebuffer_index=0; // return mb_recievebuffer_index; // } _hardfault_was_inside_readwrite=1; return -1; } }

int32_t write_serial(const uint8_t buf, uint16_t count, int32_t byte_timeout_ms, void arg) { return count; while(mcu_tracer_usart_send_busy()){ delay1msec(); byte_timeout_ms--; if(byte_timeout_ms<1) break; } MBHW_dir_set_write(); //delay1msec(); mcu_tracer_usart_send(buf,count); mcu_tracer_usart_txdone_wait(); //even when the transmission is done, one last byte is processing, therefore this delay! uint32_t countdown=2000; while(countdown--) asm(""); MBHW_dir_set_read();

return count; }

void onError() { // Set the led ON on error }

nmbs_error handle_read_coils(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out, uint8_t unit_id, void *arg) { return NMBS_ERROR_NONE; //deactive funciton to avoid errors if (address + quantity > COILS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;

// Read our coils values into coils_out for (int i = 0; i < quantity; i++) { bool value = nmbs_bitfield_read(server_coils, address + i); nmbs_bitfield_write(coils_out, i, value); }

return NMBS_ERROR_NONE; }

nmbs_error handle_write_multiple_coils(uint16_t address, uint16_t quantity, const nmbs_bitfield coils, uint8_t unit_id, void *arg) { if (address + quantity > COILS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;

// Write coils values to our server_coils for (int i = 0; i < quantity; i++) { nmbs_bitfield_write(server_coils, address + i, nmbs_bitfield_read(coils, i)); }

return NMBS_ERROR_NONE; }

nmbs_error handler_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t registers_out, uint8_t unit_id, void arg) { if (address + quantity > REGS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;

// Read our registers values into registers_out for (int i = 0; i < quantity; i++) registers_out[i] = server_registers[address + i];

return NMBS_ERROR_NONE; }

nmbs_error handle_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t registers, uint8_t unit_id, void arg) { if (address + quantity > REGS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;

// Write registers values to our server_registers for (int i = 0; i < quantity; i++) server_registers[address + i] = registers[i];

return NMBS_ERROR_NONE; }

void Nanomb_init(void) { nmbs_platform_conf platform_conf; platform_conf.transport = NMBS_TRANSPORT_RTU; platform_conf.read = read_serial; platform_conf.write = write_serial; platform_conf.arg = NULL;

nmbs_callbacks callbacks = {0}; callbacks.read_coils = handle_read_coils; callbacks.write_multiple_coils = handle_write_multiple_coils; callbacks.read_holding_registers = handler_read_holding_registers; callbacks.write_multiple_registers = handle_write_multiple_registers;

// Create the modbus server

nmbs_error err = nmbs_server_create(&nmbs, RTU_SERVER_ADDRESS, &platform_conf, &callbacks); if (err != NMBS_ERROR_NONE) { onError(); }

nmbs_set_read_timeout(&nmbs, 1000); nmbs_set_byte_timeout(&nmbs, 100); }

void nanomb_task(void){ char fakedata[8]={0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x3D, 0xCC}; fake_data(&fakedata[0],8); nmbs_server_poll(&nmbs); } `

greenscreenflicker commented 5 months ago

@debevv ping

debevv commented 5 months ago

Hi, unfortunately I really don't have the time to inspect this... I see that your platform is RISC-V, so there may be a minuscule chance that the problem lies inside some non cross-platform code in the library, but first I would like to be 100% sure that it's not just a bug in your application.
Can you try to test the code on linux or on arduino, maybe with a debugger?