Merge branch 'bugfix/freemodbus_fix_nvs_access_failure' into 'master'

modbus master example fix nvs access failure

Closes IDF-1054, IDFGH-1840, and IDFGH-1943

See merge request espressif/esp-idf!6241
This commit is contained in:
Angus Gratton 2019-11-08 16:55:42 +08:00
commit 65c67faa6a
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 );
}
}
}
}