Tool/software: Code Composer Studio
Hello everyone,
I'm trying to implement the Modbus protocol on the TM4C123G using the FreeMODBUS Stack. But the problem seems like happen on the hardware setup, here are the codes that I use
For the 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$ */ #ifndef _PORT_H #define _PORT_H #include <assert.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> #include "inc/tm4c123gh6pm.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_sysctl.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" #define INLINE inline #define PR_BEGIN_EXTERN_C extern "C" { #define PR_END_EXTERN_C } #define ENTER_CRITICAL_SECTION( ) IntMasterDisable(); #define EXIT_CRITICAL_SECTION( ) 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
For the portserial.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$
*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#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|UART_INT_RT);
UARTIntRegister(UART0_BASE,&prvvUARTRxISR);
}
else
UARTIntDisable(UART0_BASE,UART_INT_RX);
if( xTxEnable )
{
UARTIntEnable(UART0_BASE, UART_INT_TX);
UARTIntRegister(UART0_BASE,&prvvUARTTxReadyISR);
}
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.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//
// Enable UART0
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
//
// Configure GPIO Pins for UART mode.
//
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
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.
//
UARTConfigSetExpClk(UART0_BASE, 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
//
UARTIntEnable(UART0_BASE, UART_INT_RX|UART_INT_RT);
UARTIntRegister(UART0_BASE,&prvvUARTRxISR);
UARTEnable(UART0_BASE);
return FALSE;
}
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);
if(UARTCharsAvail(UART0_BASE))
{
UARTCharPut(UART0_BASE, UARTCharGet(UART0_BASE));
}
return TRUE;
}
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
*/
UARTIntClear(UART0_BASE,UARTIntStatus(UART0_BASE,true));
while (UARTCharsAvail(UART0_BASE))
{
*pucByte = UARTCharGetNonBlocking(UART0_BASE);
}
return TRUE;
}
/* 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.
*/
static void prvvUARTTxReadyISR( void )
{
pxMBFrameCBTransmitterEmpty( );
}
/* 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.
*/
static void prvvUARTRxISR( void )
{
pxMBFrameCBByteReceived( );
}
For porttimer.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$
*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
uint32_t a;
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_ONE_SHOT);
a = usTim1Timerout50us*SysCtlClockGet()/20000-1;
TimerLoadSet(TIMER0_BASE, TIMER_A, a);
TimerIntRegister(TIMER0_BASE, TIMER_A, &prvvTIMERExpiredISR);
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
IntMasterEnable();
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4);
return FALSE;
}
inline void
vMBPortTimersEnable( )
{
/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
TimerEnable(TIMER0_BASE, TIMER_A);
}
inline void
vMBPortTimersDisable( )
{
/* Disable any pending timers. */
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
}
/* 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.
*/
static void prvvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired( );
}
For the main.c
/* * FreeModbus Libary: BARE Demo Application * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id$ */ /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" #include <stdint.h> #include <stdbool.h> #include "inc/tm4c123gh6pm.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" /* ----------------------- Defines ------------------------------------------*/ #define REG_INPUT_START 3000 #define REG_INPUT_NREGS 4 /* ----------------------- Static variables ---------------------------------*/ static USHORT usRegInputStart = REG_INPUT_START; static USHORT usRegInputBuf[REG_INPUT_NREGS]; /* ----------------------- Start implementation -----------------------------*/ void Configuration() { SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);// 16 MHz clk SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 ); SysCtlDelay(100000); GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 , 0); } int main( void ) { eMBErrorCode eStatus; Configuration(); eStatus = eMBInit( MB_RTU, 0x0A, 0, 9600, MB_PAR_EVEN ); /* Enable the Modbus Protocol Stack. */ eStatus = eMBEnable(); // eMBClose(); for( ;; ) { ( void )eMBPoll( ); /* Here we simply count the number of poll cycles. */ usRegInputBuf[0]++; usRegInputBuf[1] = 5; usRegInputBuf[2] = 6; usRegInputBuf[3] = 33; } } 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; }
After testing, I found out that the microcontroller still receive the data but don't process it. It may because of the timer setup but I'm not sure because there are no output to observe. I try using GPIO led to keep track on the data process but when it comes to the timer, the interrupt condition may block it.
Please help me with this. I did look up for Modbus implementation on TM4C but there is no solution that help, so I don't know what to do next.