freemodbus: fix nvs access failure

place timer handler functions into IRAM
update timer port handlers
fix communication issues
fix offset issue in example
add kconfig option to place handlers into IRAM
This commit is contained in:
Alex Lisitsyn 2019-11-08 16:55:42 +08:00 committed by Angus Gratton
parent ba72de2099
commit 1ab9e81729
18 changed files with 187 additions and 160 deletions

View file

@ -113,7 +113,7 @@ menu "Modbus configuration"
range 0 1
default 0
help
Modbus Timer group number that is used for timeout measurement.
Modbus Timer group number that is used for timeout measurement.
config FMB_TIMER_INDEX
int "Modbus Timer index in the group"
@ -122,4 +122,14 @@ menu "Modbus configuration"
help
Modbus Timer Index in the group that is used for timeout measurement.
config FMB_ISR_IN_IRAM
bool "Place interrupt handlers into IRAM"
default y
select UART_ISR_IN_IRAM
help
This option places Modbus IRQ handlers into IRAM.
This allows to avoid delays related to processing of non-IRAM-safe interrupts
during a flash write operation (NVS updating a value, or some other
flash API which has to perform an read/write operation and disable CPU cache).
endmenu

View file

@ -45,7 +45,7 @@ esp_err_t mbc_master_init(mb_port_type_t port_type, void** handler)
MB_MASTER_CHECK((port_handler != NULL),
ESP_ERR_INVALID_STATE,
"Master interface initialization failure, error=(0x%x), port type=(0x%x).",
(uint16_t)error, (uint16_t)port_type);
error, (uint16_t)port_type);
if ((port_handler != NULL) && (error == ESP_OK)) {
master_interface_ptr = (mb_master_interface_t*) port_handler;
@ -106,9 +106,9 @@ esp_err_t mbc_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uin
"Master interface is not correctly initialized.");
error = master_interface_ptr->get_parameter(cid, name, value, type);
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master get parameter failure error=(0x%x).",
(uint16_t)error);
error,
"SERIAL master get parameter failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return error;
}
@ -126,10 +126,10 @@ esp_err_t mbc_master_send_request(mb_param_request_t* request, void* data_ptr)
"Master interface is not correctly initialized.");
error = master_interface_ptr->send_request(request, data_ptr);
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master get parameter failure error=(0x%x).",
(uint16_t)error);
return error;
error,
"SERIAL master send request failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return ESP_OK;
}
/**
@ -146,10 +146,10 @@ esp_err_t mbc_master_set_descriptor(const mb_parameter_descriptor_t* descriptor,
"Master interface is not correctly initialized.");
error = master_interface_ptr->set_descriptor(descriptor, num_elements);
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master set descriptor failure error=(0x%x).",
(uint16_t)error);
return error;
error,
"SERIAL master set descriptor failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return ESP_OK;
}
/**
@ -166,10 +166,10 @@ esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uin
"Master interface is not correctly initialized.");
error = master_interface_ptr->set_parameter(cid, name, value, type);
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master set parameter failure error=(0x%x).",
(uint16_t)error);
return error;
error,
"SERIAL master set parameter failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return ESP_OK;
}
/**
@ -186,10 +186,10 @@ esp_err_t mbc_master_setup(void* comm_info)
"Master interface is not correctly initialized.");
error = master_interface_ptr->setup(comm_info);
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master setup failure error=(0x%x).",
(uint16_t)error);
return error;
error,
"SERIAL master setup failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return ESP_OK;
}
/**
@ -206,10 +206,10 @@ esp_err_t mbc_master_start(void)
"Master interface is not correctly initialized.");
error = master_interface_ptr->start();
MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE,
"SERIAL master start failure error=(0x%x).",
(uint16_t)error);
return error;
error,
"SERIAL master start failure error=(0x%x) (%s).",
error, esp_err_to_name(error));
return ESP_OK;
}
eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress,

View file

@ -113,7 +113,7 @@ eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP
ENTER_CRITICAL_SECTION( );
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
{
eStatus = MB_EPORTERR;
}
@ -388,27 +388,21 @@ xMBASCIITransmitFSM( void )
* been sent. */
case STATE_TX_NOTIFY:
eSndState = STATE_TX_IDLE;
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
xMBPortEventPost( EV_FRAME_SENT );
xNeedPoll = TRUE;
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBPortSerialEnable( TRUE, FALSE );
eSndState = STATE_TX_IDLE;
break;
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBPortSerialEnable( TRUE, FALSE );
break;
}
return xNeedPoll;
}
BOOL
xMBASCIITimerT1SExpired( void )
BOOL MB_PORT_ISR_ATTR xMBASCIITimerT1SExpired( void )
{
switch ( eRcvState )
{
@ -421,7 +415,8 @@ xMBASCIITimerT1SExpired( void )
break;
default:
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF )
|| (eRcvState == STATE_RX_IDLE ));
break;
}
vMBPortTimersDisable( );

View file

@ -130,6 +130,9 @@ PR_BEGIN_EXTERN_C
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
/*! \brief Check the option to place handlers into IRAM */
#define MB_ISR_IN_IRAM ( CONFIG_FMB_ISR_IN_IRAM )
/*! @} */
#ifdef __cplusplus
PR_END_EXTERN_C

View file

@ -37,6 +37,20 @@
PR_BEGIN_EXTERN_C
#endif
#if CONFIG_UART_ISR_IN_IRAM
#define MB_PORT_SERIAL_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define MB_PORT_SERIAL_ISR_FLAG ESP_INTR_FLAG_LOWMED
#endif
#if MB_ISR_IN_IRAM
#define MB_PORT_ISR_ATTR IRAM_ATTR
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define MB_PORT_ISR_ATTR
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_LOWMED
#endif
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
@ -47,7 +61,7 @@ typedef enum
EV_FRAME_SENT = 0x08 /*!< Frame sent. */
} eMBEventType;
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED
typedef enum {
EV_MASTER_NO_EVENT = 0x0000,
EV_MASTER_READY = 0x0001, /*!< Startup finished. */

View file

@ -48,7 +48,7 @@
#include "mbrtu.h"
#endif
#if MB_MASTER_ASCII_ENABLED == 1
#include "mbascii.h"
#include "mbascii_m.h"
#endif
#if MB_MASTER_TCP_ENABLED == 1
#include "mbtcp.h"
@ -56,7 +56,6 @@
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifndef MB_PORT_HAS_CLOSE
#define MB_PORT_HAS_CLOSE 1
#endif
@ -269,15 +268,13 @@ eMBMasterPoll( void )
eMBMasterErrorEventType errorType;
/* Check if the protocol stack is ready. */
if( eMBState != STATE_ENABLED )
{
if( eMBState != STATE_ENABLED ) {
return MB_EILLSTATE;
}
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if( xMBMasterPortEventGet( &eEvent ) == TRUE )
{
if( xMBMasterPortEventGet( &eEvent ) == TRUE ) {
switch ( eEvent )
{
case EV_MASTER_NO_EVENT:
@ -303,13 +300,10 @@ eMBMasterPoll( void )
case EV_MASTER_FRAME_RECEIVED:
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
// Check if the frame is for us. If not ,send an error process event.
if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) )
{
if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) ) {
ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
}
else
{
} else {
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
ESP_LOGD(MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).", __func__, ucRcvAddress, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
@ -322,13 +316,10 @@ eMBMasterPoll( void )
/* If receive frame has exception. The receive function code highest bit is 1.*/
if(ucFunctionCode >> 7) {
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
}
else
{
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
{
} else {
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++) {
/* No more function handlers registered. Abort. */
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
break;
}
else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
@ -342,8 +333,7 @@ eMBMasterPoll( void )
vMBMasterSetDestAddress(j);
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
}
else {
} else {
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
vMBMasterSetCBRunInMasterMode(FALSE);
@ -355,8 +345,7 @@ eMBMasterPoll( void )
if (eException != MB_EX_NONE) {
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
else {
} else {
vMBMasterCBRequestSuccess( );
vMBMasterRunResRelease( );
}
@ -366,8 +355,7 @@ eMBMasterPoll( void )
/* Master is busy now. */
vMBMasterGetPDUSndBuf( &ucMBFrame );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
if (eStatus != MB_ENOERR)
{
if (eStatus != MB_ENOERR) {
ESP_LOGD(MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus);
}
@ -438,7 +426,7 @@ eMBMasterErrorEventType eMBMasterGetErrorType( void )
}
// Set Modbus Master current error event type.
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
void IRAM_ATTR vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
{
eMBMasterCurErrorType = errorType;
}

View file

@ -249,7 +249,7 @@ xMBRTUReceiveFSM( void )
/* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE.
* receiver is in the state STATE_RX_RCV.
*/
case STATE_RX_IDLE:
usRcvBufferPos = 0;
@ -292,8 +292,6 @@ xMBRTUTransmitFSM( void )
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBPortSerialEnable( TRUE, FALSE );
break;
case STATE_TX_XMIT:
@ -306,11 +304,10 @@ xMBRTUTransmitFSM( void )
}
else
{
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBPortSerialEnable( TRUE, FALSE );
xMBPortEventPost( EV_FRAME_SENT );
xNeedPoll = TRUE;
eSndState = STATE_TX_IDLE;
vMBPortTimersEnable( );
}
break;
}
@ -318,7 +315,7 @@ xMBRTUTransmitFSM( void )
return xNeedPoll;
}
BOOL
BOOL MB_PORT_ISR_ATTR
xMBRTUTimerT35Expired( void )
{
BOOL xNeedPoll = FALSE;
@ -342,8 +339,7 @@ xMBRTUTimerT35Expired( void )
/* Function called in an illegal state. */
default:
assert( ( eRcvState == STATE_RX_INIT ) ||
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
assert( ( eRcvState == STATE_RX_IDLE ) || ( eRcvState == STATE_RX_ERROR ) );
}
vMBPortTimersDisable( );

View file

@ -69,12 +69,15 @@ typedef enum
STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */
} eMBMasterSndState;
/*------------------------ Shared variables ---------------------------------*/
volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
/* ----------------------- Static variables ---------------------------------*/
static volatile eMBMasterSndState eSndState;
static volatile eMBMasterRcvState eRcvState;
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
static volatile USHORT usMasterSendPDULength;
static volatile UCHAR *pucMasterSndBufferCur;
@ -260,7 +263,7 @@ xMBMasterRTUReceiveFSM( void )
/* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE and disable early
* receiver is in the state STATE_M_RX_RCV and disable early
* the timer of respond timeout .
*/
case STATE_M_RX_IDLE:
@ -310,11 +313,10 @@ xMBMasterRTUTransmitFSM( void )
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_M_TX_XFWR:
xNeedPoll = TRUE;
break;
case STATE_M_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBMasterPortSerialEnable( TRUE, FALSE );
break;
case STATE_M_TX_XMIT:
@ -328,9 +330,6 @@ xMBMasterRTUTransmitFSM( void )
else
{
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBMasterPortSerialEnable( TRUE, FALSE );
eSndState = STATE_M_TX_XFWR;
/* If the frame is broadcast ,master will enable timer of convert delay,
* else master will enable timer of respond timeout. */
@ -342,7 +341,6 @@ xMBMasterRTUTransmitFSM( void )
{
vMBMasterPortTimersRespondTimeoutEnable( );
}
xNeedPoll = TRUE;
}
break;
}
@ -350,8 +348,7 @@ xMBMasterRTUTransmitFSM( void )
return xNeedPoll;
}
BOOL
xMBMasterRTUTimerExpired(void)
BOOL MB_PORT_ISR_ATTR xMBMasterRTUTimerExpired(void)
{
BOOL xNeedPoll = FALSE;
@ -395,8 +392,7 @@ xMBMasterRTUTimerExpired(void)
break;
/* Function called in an illegal state. */
default:
assert(
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
assert(( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
break;
}
eSndState = STATE_M_TX_IDLE;

View file

@ -30,7 +30,7 @@
#define MB_PORT_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MB_PORT_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
return ret_val; \
}
#ifdef __cplusplus

View file

@ -56,7 +56,7 @@
/* ----------------------- Variables ----------------------------------------*/
static xQueueHandle xQueueHdl;
#define MB_EVENT_QUEUE_SIZE (1)
#define MB_EVENT_QUEUE_SIZE (6)
#define MB_EVENT_QUEUE_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_EVENT_QUEUE_TIMEOUT))
/* ----------------------- Start implementation -----------------------------*/
@ -82,21 +82,27 @@ vMBPortEventClose( void )
}
}
BOOL
BOOL MB_PORT_ISR_ATTR
xMBPortEventPost( eMBEventType eEvent )
{
BOOL bStatus = TRUE;
BaseType_t xStatus, xHigherPriorityTaskWoken = pdFALSE;
assert(xQueueHdl != NULL);
if( (BOOL)xPortInIsrContext() == TRUE )
{
xQueueSendFromISR(xQueueHdl, (const void*)&eEvent, pdFALSE);
xStatus = xQueueSendFromISR(xQueueHdl, (const void*)&eEvent, &xHigherPriorityTaskWoken);
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
if ( xHigherPriorityTaskWoken )
{
portYIELD_FROM_ISR();
}
}
else
{
xQueueSend(xQueueHdl, (const void*)&eEvent, MB_EVENT_QUEUE_TIMEOUT);
xStatus = xQueueSend(xQueueHdl, (const void*)&eEvent, MB_EVENT_QUEUE_TIMEOUT);
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
}
return bStatus;
return TRUE;
}
BOOL

View file

@ -79,7 +79,7 @@ xMBMasterPortEventInit( void )
return TRUE;
}
BOOL
BOOL MB_PORT_ISR_ATTR
xMBMasterPortEventPost( eMBMasterEventType eEvent )
{
BOOL bStatus = FALSE;
@ -140,10 +140,7 @@ xMBMasterPortEventGet( eMBMasterEventType * eEvent)
void vMBMasterOsResInit( void )
{
xSemaphorMasterHdl = xSemaphoreCreateBinary();
if (xSemaphorMasterHdl == NULL)
{
ESP_LOGE(MB_PORT_TAG,"%s: OS semaphore create error.", __func__);
}
MB_PORT_CHECK((xSemaphorMasterHdl != NULL), ; , "%s: OS semaphore create error.", __func__);
}
/**
@ -156,15 +153,13 @@ void vMBMasterOsResInit( void )
*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{
BOOL xResult = FALSE;
BaseType_t xStatus = pdTRUE;
// If waiting time is -1. It will wait forever
xStatus = xSemaphoreTake(xSemaphorMasterHdl, lTimeOut );
if (xStatus == pdTRUE) {
xResult = TRUE;
}
return xResult;
MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s:Take resource failure.", __func__);
ESP_LOGV(MB_PORT_TAG,"%s:Take resource (%lu ticks).", __func__, lTimeOut);
return TRUE;
}
/**
@ -173,11 +168,9 @@ BOOL xMBMasterRunResTake( LONG lTimeOut )
*/
void vMBMasterRunResRelease( void )
{
BaseType_t xStatus = pdTRUE;
BaseType_t xStatus = pdFALSE;
xStatus = xSemaphoreGive(xSemaphorMasterHdl);
if (xStatus != pdTRUE) {
ESP_LOGE(MB_PORT_TAG,"%s: resource release failure.", __func__);
}
MB_PORT_CHECK((xStatus == pdTRUE), ; , "%s: resource release failure.", __func__);
}
/**
@ -192,9 +185,7 @@ void vMBMasterRunResRelease( void )
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);
if(ret != TRUE) {
ESP_LOGE(MB_PORT_TAG, "Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!!!");
}
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!", __func__);
ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__);
}
@ -209,9 +200,7 @@ void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);
if(ret != TRUE) {
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!!!");
}
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!", __func__);
ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__);
}
@ -228,9 +217,8 @@ void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, U
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);
if(ret != TRUE) {
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!!!");
}
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!", __func__);
ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data timeout failure.", __func__);
}
/**
@ -244,9 +232,8 @@ void vMBMasterCBRequestSuccess( void ) {
* If you don't use OS, you can change it.
*/
BOOL ret = xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS);
if (ret != TRUE) {
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_PROCESS_SUCCESS' failed!!!");
}
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_PROCESS_SUCCESS' failed!", __func__);
ESP_LOGD(MB_PORT_TAG,"%s: Callback request success.", __func__);
}
/**
@ -284,7 +271,7 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eErrStatus = MB_MRE_EXE_FUN;
}
} else {
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, xRecvedEvent);
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, uxBits);
assert(0);
}
return eErrStatus;

View file

@ -67,6 +67,8 @@
#define MB_SERIAL_TASK_STACK_SIZE (CONFIG_FMB_SERIAL_TASK_STACK_SIZE)
#define MB_SERIAL_TOUT (3) // 3.5*8 = 28 ticks, TOUT=3 -> ~24..33 ticks
#define MB_SERIAL_TX_TOUT_MS (100)
#define MB_SERIAL_TX_TOUT_TICKS pdMS_TO_TICKS(MB_SERIAL_TX_TOUT_MS) // timeout for transmission
// Set buffer size for transmission
#define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE)
@ -125,14 +127,13 @@ static void vMBPortSerialRxPoll(size_t xEventSize)
// Let the stack know that T3.5 time is expired and data is received
(void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired();
#endif
ESP_LOGD(TAG, "RX_T35_timeout: %d(bytes in buffer)\n", (uint32_t)usLength);
ESP_LOGD(TAG, "Receive: %d(bytes in buffer)\n", (uint32_t)usLength);
}
}
}
BOOL xMBPortSerialTxPoll(void)
{
BOOL bStatus = FALSE;
USHORT usCount = 0;
BOOL bNeedPoll = FALSE;
@ -142,10 +143,14 @@ BOOL xMBPortSerialTxPoll(void)
// Calls the modbus stack callback function to let it fill the UART transmit buffer.
bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // calls callback xMBRTUTransmitFSM();
}
ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes\n", (uint16_t)usCount);
bStatus = TRUE;
ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount);
// Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
vMBPortSerialEnable(TRUE, FALSE);
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
return TRUE;
}
return bStatus;
return FALSE;
}
static void vUartTask(void *pvParameters)
@ -154,7 +159,6 @@ static void vUartTask(void *pvParameters)
for(;;) {
if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) {
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber);
//vMBPortTimersEnable();
switch(xEvent.type) {
//Event of UART receving data
case UART_DATA:
@ -246,7 +250,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr);
// Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, ESP_INTR_FLAG_LEVEL3);
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr);
#ifndef MB_TIMER_PORT_ENABLED

View file

@ -114,7 +114,7 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize)
}
// The buffer is transferred into Modbus stack and is not needed here any more
uart_flush_input(ucUartNumber);
ESP_LOGD(TAG, "RX_T35_timeout: %d(bytes in buffer)\n", (uint32_t)usLength);
ESP_LOGD(TAG, "Receive: %d(bytes in buffer)\n", (uint32_t)usLength);
}
} else {
ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, (uint16_t)xEventSize);
@ -123,7 +123,6 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize)
BOOL xMBMasterPortSerialTxPoll(void)
{
BOOL bStatus = FALSE;
USHORT usCount = 0;
BOOL bNeedPoll = FALSE;
@ -137,10 +136,11 @@ BOOL xMBMasterPortSerialTxPoll(void)
// Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
bTxStateEnabled = FALSE;
vMBMasterPortSerialEnable( TRUE, FALSE );
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
bStatus = TRUE;
return TRUE;
}
return bStatus;
return FALSE;
}
// UART receive event task
@ -241,7 +241,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr);
// Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, ESP_INTR_FLAG_LEVEL3);
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr);
// Set timeout for TOUT interrupt (T3.5 modbus time)

View file

@ -112,7 +112,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
(uint32_t)xErr);
// Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr,
(void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_LOWMED, &xTimerIntHandle);
(void*)(uint32_t)usTimerIndex, MB_PORT_TIMER_ISR_FLAG, &xTimerIntHandle);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr);
@ -130,13 +130,18 @@ void vMBPortTimersEnable(void)
#endif
}
void vMBPortTimersDisable(void)
void MB_PORT_ISR_ATTR
vMBPortTimersDisable(void)
{
#ifdef CONFIG_FMB_TIMER_PORT_ENABLED
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
if( (BOOL)xPortInIsrContext() ) {
timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE);
} else {
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
}
#endif
}

View file

@ -109,7 +109,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
(uint32_t)xErr);
// Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex,
vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_LOWMED, &xTimerIntHandle);
vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, MB_PORT_TIMER_ISR_FLAG, &xTimerIntHandle);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr);
@ -179,13 +179,18 @@ void vMBMasterPortTimersRespondTimeoutEnable(void)
(void)xMBMasterPortTimersEnable(usTimerTicks);
}
void vMBMasterPortTimersDisable(void)
void MB_PORT_ISR_ATTR
vMBMasterPortTimersDisable()
{
// Stop timer and then reload timer counter value
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
if( (BOOL)xPortInIsrContext() ) {
timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE);
} else {
// Stop timer and then reload timer counter value
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
}
}
void vMBMasterPortTimerClose(void)

View file

@ -36,10 +36,17 @@
extern BOOL xMBMasterPortSerialTxPoll(void);
/*-----------------------Master mode use these variables----------------------*/
#define MODE_RTU
#ifdef MODE_RTU
#define MB_DT_SIZE(size) ((size << 1) + 8)
#else
#define MB_DT_SIZE(size) ((size << 2) + 20)
#endif
// The response time is average processing time + data transmission (higher on lower speeds)
// ~resp_time_ms = min_pcocessing_time_ms + ((2 packets * (header_size + packet_bytes)) * 11 bits in byte * 1000 ms_in_sec) / transmit_speed))
#define MB_RESPONSE_TIMEOUT(size) pdMS_TO_TICKS(30 + (2 * ((size << 1) + 8) * 11 * 1000 / mb_speed))
#define MB_RESPONSE_TIMEOUT(mb_speed, size) pdMS_TO_TICKS( 30 + (2 * MB_DT_SIZE(size) * 11 * 1000 / mb_speed))
#define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
@ -190,8 +197,8 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
uint16_t mb_size = request->reg_size;
uint32_t mb_speed = mbm_opts->mbm_comm.baudrate;
// Timeout value for packet processing
uint32_t timeout = 0;
// Timeout value for last processed packet
static uint32_t timeout = MB_RESPONSE_TICS;
size_t pack_length = 0;
// Set the buffer for callback function processing of received data
@ -203,53 +210,53 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
{
case MB_FUNC_READ_COILS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size , (LONG)timeout );
break;
case MB_FUNC_WRITE_SINGLE_COIL:
timeout = MB_RESPONSE_TIMEOUT(1);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, 1);
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
*(USHORT*)data_ptr, (LONG)timeout );
break;
case MB_FUNC_WRITE_MULTIPLE_COILS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (UCHAR*)data_ptr, (LONG)timeout);
break;
case MB_FUNC_READ_DISCRETE_INPUTS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG)timeout );
break;
case MB_FUNC_READ_HOLDING_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(mb_size);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG)timeout );
break;
case MB_FUNC_WRITE_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(1);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, 1);
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
*(USHORT*)data_ptr, (LONG)timeout );
break;
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
timeout = MB_RESPONSE_TIMEOUT(mb_size);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
(USHORT)mb_offset, (USHORT)mb_size,
(USHORT*)data_ptr, (LONG)timeout );
break;
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
timeout = MB_RESPONSE_TIMEOUT(mb_size << 1);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size << 1);
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (USHORT*)data_ptr,
(USHORT)mb_offset, (USHORT)mb_size,
(LONG)timeout );
break;
case MB_FUNC_READ_INPUT_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(mb_size);
timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG) timeout );
break;
@ -268,18 +275,25 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
break;
case MB_MRE_NO_REG:
error = ESP_ERR_NOT_SUPPORTED;
error = ESP_ERR_NOT_SUPPORTED; // Invalid register request
break;
case MB_MRE_TIMEDOUT:
error = ESP_ERR_TIMEOUT;
error = ESP_ERR_TIMEOUT; // Slave did not send response
break;
case MB_MRE_EXE_FUN:
case MB_MRE_REV_DATA:
error = ESP_ERR_INVALID_RESPONSE;
error = ESP_ERR_INVALID_RESPONSE; // Invalid response from slave
break;
case MB_MRE_MASTER_BUSY:
error = ESP_ERR_INVALID_STATE; // Master is busy (previous request is pending
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
__FUNCTION__, mb_error);
error = ESP_FAIL;
break;
}

View file

@ -55,7 +55,7 @@
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif /* __cplusplus */
void vMBPortSetMode( UCHAR ucMode );
#ifdef __cplusplus

View file

@ -48,7 +48,11 @@ static void modbus_slave_task(void *pvParameters)
// Check if stack started then poll for data
if (status & MB_EVENT_STACK_STARTED) {
(void)eMBPoll(); // allow stack to process data
(void)xMBPortSerialTxPoll(); // Send response buffer if ready
// Send response buffer
BOOL xSentState = xMBPortSerialTxPoll();
if (xSentState) {
(void)xMBPortEventPost( EV_FRAME_SENT );
}
}
}
}