Hi Everyone!
I'm trying to implement the Freemodbus stack in my Tm4C123GH6PM and i've already make some tests but with no success.
Hope to get some help or advice thank you very much, here are the steps i've done
1.- First, i downloaded the freemodbus-v 1.4.0 folder and make the "changes" in the corresponding port folder,
port.h
/* * FreeModbus Libary: BARE Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: port.h,v 1.1 2006/08/22 21:35:13 wolti Exp $ */ #ifndef _PORT_H #define _PORT_H /* ----------------------- Platform includes --------------------------------*/ #include "IncTm4c123.h" #include <assert.h> #define INLINE inline #define PR_BEGIN_EXTERN_C extern "C" { #define PR_END_EXTERN_C } #define ENTER_CRITICAL_SECTION( ) ROM_IntMasterDisable() #define EXIT_CRITICAL_SECTION( ) ROM_IntMasterEnable() typedef uint8_t BOOL; typedef unsigned char UCHAR; typedef char CHAR; typedef uint16_t USHORT; typedef int16_t SHORT; typedef uint32_t ULONG; typedef int32_t LONG; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #endif
So, the .h file IncTm4c123.h is only a header file where i'm putting the corresponding header files to use the peripheral functions, i forgot to mention that i'm using TivaWare 2.1.4.178 and the IDE is IAR 8.0
The constants: ENTER_CRITICAL_SECTION & EXIT_CRITICAL_SECTION as i understand are used or needed to disable the interrupts on the device object so, i disable all the Processor Interrupts
Following with the porting.dox file, the next file to change is
porttimer.c
/* ----------------------- Platform includes --------------------------------*/ #include "port.h" #include "IncTm4c123.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- static functions ---------------------------------*/ //static void prvvTIMERExpiredISR( void ); /* ----------------------- my functions -------------------------------------*/ USHORT usMBMulDiv(USHORT a, USHORT b, USHORT c); /* ----------------------- Persistent variable ------------------------------*/ USHORT usDelta; /* ----------------------- Start implementation -----------------------------*/ USHORT usMBMulDiv(USHORT a, USHORT b, USHORT c){ ULONG x; x = a; x *= b; x /= c; return ( USHORT ) x; } //the time argument usTim1Timerout50us is in multiples of 50us //so in order to calculate the timer ticks use the function usMBMulDiv BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) { ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_ONE_SHOT);//Full width 32bits and for freemodmus requirements Timer needs to be one-shot //Define number to load in register usDelta = usMBMulDiv(usTim1Timerout50us, 800, 100); ROM_IntMasterEnable();//enable all processor int ROM_IntEnable(INT_TIMER0A);//inc/hw_ints.h header defines ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);//select timer source// TIMEOUT interrupt return TRUE; } void vMBPortTimersEnable( )//only starts the timer { /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */ ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, usDelta); ROM_TimerEnable(TIMER0_BASE, TIMER_A);//enable timer ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); } void vMBPortTimersDisable( ) { /* Disable any pending timers. */ ROM_TimerDisable(TIMER0_BASE,TIMER_A); ROM_TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); } /* Create an ISR which is called whenever the timer has expired. This function * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that * the timer has expired. */ void Timer0IntHandler( void ) { ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ROM_TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ( void )pxMBPortCBTimerExpired( ); }
I've test this part with the code sugested:
xMBPortTimersInit(20); vMBPortTimersEnable();
and it seems that work fine just put to turn-on a LED in the ISR of the Timer0 (Timer0IntHandler(void))
The next one...
portserial.c
#include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- static functions ---------------------------------*/ /*static void prvvUARTTxReadyISR( void ); static void prvvUARTRxISR( void ); */ /* ----------------------- Start implementation -----------------------------*/ void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) { /* If xRXEnable enable serial receive interrupts. If xTxENable enable * transmitter empty interrupts. */ if( xRxEnable ) { UARTIntEnable(UART0_BASE,UART_INT_RX); }else UARTIntDisable(UART0_BASE,UART_INT_RX); if( xTxEnable ) { UARTIntEnable(UART0_BASE,UART_INT_TX); }else UARTIntDisable(UART0_BASE,UART_INT_TX); } BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { (void)ucPORT; uint32_t Parity,Bits,StopBits; // // Enable the GPIO Peripheral used by the UART. // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // // Enable UART0 // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // // Configure GPIO Pins for UART mode. // ROM_GPIOPinConfigure(GPIO_PA0_U0RX); ROM_GPIOPinConfigure(GPIO_PA1_U0TX); ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // // Select the length and Parity of UART // switch( eParity ) { case MB_PAR_EVEN: Parity = UART_CONFIG_PAR_EVEN; StopBits = UART_CONFIG_STOP_ONE; break; case MB_PAR_ODD: Parity = UART_CONFIG_PAR_ODD; StopBits = UART_CONFIG_STOP_ONE; break; case MB_PAR_NONE: Parity = UART_CONFIG_PAR_NONE; StopBits = UART_CONFIG_STOP_TWO;//Ensure the 11 bits of RTU character format break; } switch( ucDataBits ) { case 8: Bits = UART_CONFIG_WLEN_8; break; case 7: Bits = UART_CONFIG_WLEN_7; break; } // // Initialize the UART for console I/O. // ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), ulBaudRate, (Bits | StopBits | Parity)); //Disable the fifo in order to ensure the interrupt is only for a change in RX UARTFIFODisable(UART0_BASE); // // Enable UART & Interrupts // ROM_IntEnable(INT_UART0); // vMBPortSerialEnable(TRUE,TRUE); return TRUE; } BOOL xMBPortSerialPutByte( CHAR ucByte ) { /* Put a byte in the UARTs transmit buffer. This function is called * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been * called. */ UARTCharPut( UART0_BASE, ucByte ); return TRUE; } BOOL xMBPortSerialGetByte( CHAR * pucByte )//give an @ to put the new char { /* Return the byte in the UARTs receive buffer. This function is called * by the protocol stack after pxMBFrameCBByteReceived( ) has been called. */ // // No FIFO. // do { *pucByte = ROM_UARTCharGet(UART0_BASE); }while (ROM_UARTCharsAvail(UART0_BASE)); return TRUE; } void UARTIntHandler( void ) { uint32_t ui32status; ui32status = ROM_UARTIntStatus(UART0_BASE,true); /* Create an interrupt handler for the receive interrupt for your target * processor. This function should then call pxMBFrameCBByteReceived( ). The * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the * character. */ if( ui32status == UART_INT_RX) { pxMBFrameCBByteReceived( ); ROM_UARTIntClear(UART0_BASE, ui32status); } /* Create an interrupt handler for the transmit buffer empty interrupt * (or an equivalent) for your target processor. This function should then * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that * a new character can be sent. The protocol stack will then call * xMBPortSerialPutByte( ) to send the character. */ if( ui32status == UART_INT_TX) { pxMBFrameCBTransmitterEmpty( ); ROM_UARTIntClear(UART0_BASE, ui32status); } }
Here i'm not sure if it is ok to disable the FIFO of the UART but i just want to ensure that interrupt only occurs when there is a change in the pin
i only try this part of the code sending a character from my pc and turning on a LED in the uart ISR and it work fine.
Finally the main:
main.c
#include "IncTm4c123.h" #include <assert.h> #include "mb.h" #include "mbport.h" /* ----------------------- Defines ------------------------------------------*/ #define REG_INPUT_START 1000 #define REG_INPUT_NREGS 4 static unsigned usRegInputStart = REG_INPUT_START; static unsigned usRegInputBuf[REG_INPUT_NREGS]; void configure(void); eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; if( ( usAddress >= REG_INPUT_START ) && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegInputStart ); while( usNRegs > 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { return MB_ENOREG; } //-----------------------------------------------------------------------------main int main() { configure(); eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_NONE); /* Enable the Modbus Protocol Stack. */ eMBEnable( ); for( ;; ) { ( void )eMBPoll( ); /* Here we simply count the number of poll cycles. */ usRegInputBuf[0]++; } } void configure (void) { ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);// 16 MHz clk ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 ); GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 , 0); }
I only want to work with RTU mode so in mbconfig.h i put a 0 in ASCII and TCP macros, i used the Modpoll Modbus Master Simulator with linux and the parameters were:
:$./modpoll -m rtu -a 1 -r 1000 -c 4 -t 3 -b 9600 -d 8 -p none /dev/ttyACM0
No answer for the slave :/ i'm really stuck, i'm gonna try do some changes on the fifo maybe it helps but i just want to know if someone has worked with this, And tell me if I'm modifying the files correctly
Thanks and Best regards!