Hi. I'm wondering if there's available a library implementing Modbus for the KL25Z? I'm trying to port the freemodbus library but I just can't get it to work. I'm using an Arduino shield with a MAX485
and this interface for comunicating with the PC:
http://www.atac.com.tw/product/5-serial-usb/5-uc485.HTML
I tried the UART and timer functions without the modbus stack and they work fine
http://www.freemodbus.org/index.php?idx=5
http://sourceforge.net/projects/freemodbus.berlios/files/
This are the functions that I have ported:
portserial.c:
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts.
* If xTxENable enable transmitter empty interrupts.
*/
//UART0_C1 |= UART_C1_LOOPS_MASK;
/* Compute control register value */
// TIE=0,TCIE=0,RIE=0,ILIE=0,TE=1,RE=1,RWU=0,SBK=0
UART_C2_REG(UART0_BASE_PTR) |= UART_C2_TE_MASK | UART_C2_RE_MASK ;
/* Enable the requested interrupts */
if( xRxEnable )
UART_C2_REG(UART0_BASE_PTR) |= UART_C2_RIE_MASK;
if( xTxEnable )
UART_C2_REG(UART0_BASE_PTR) |= UART_C2_TIE_MASK;
}
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
uint16_t sbr;
uint16_t temp;
/* Calculate baud settings */
sbr = (uint16_t)((48000*1000)/(ulBaudRate * 16));
/* Save off the current value of the UARTx_BDH except for the SBR field */
temp = UART_BDH_REG(UART0_BASE_PTR) & ~(UART_BDH_SBR(0x1F));
UART_BDH_REG(UART0_BASE_PTR) = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8));
UART_BDL_REG(UART0_BASE_PTR) = (uint8_t)(sbr & UART_BDL_SBR_MASK);
/* Configure the serial port */
// SCI1C1 = 0x00; // LOOPS=0,SCISWAI=0,Rsrc=0,M=0,ILT=0,PE=0,PT=0
if( ucDataBits == 8 && eParity != MB_PAR_NONE )
UART_C1_REG(UART0_BASE_PTR) |= UART_C1_M_MASK;
if( eParity != MB_PAR_NONE )
UART_C1_REG(UART0_BASE_PTR) |= UART_C1_PE_MASK;
if( eParity == MB_PAR_ODD || ( eParity == MB_PAR_NONE && ucDataBits == 7 ) )
UART_C1_REG(UART0_BASE_PTR) |= UART_C1_PT_MASK;
enable_irq(12);
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. */
/* Wait until space is available in the FIFO */
while(!(UART_S1_REG(UART0_BASE_PTR) & UART_S1_TDRE_MASK));
/* Send the character */
UART_D_REG(UART0_BASE_PTR) = (uint8_t)ucByte;
UART_C2_REG(UART0_BASE_PTR) |= UART_C2_TIE_MASK ;
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.
*/
BOOL parityOK;
/* Wait until character has been received */
while (!(UART_S1_REG(UART0_BASE_PTR) & UART_S1_RDRF_MASK));
if (UART0_S1 & UART_S1_PF_MASK)
{
parityOK = 0;
}
if (!(UART0_S1 & UART_S1_PF_MASK))
{
parityOK = 1;
}
//parityOK = !SCI1S1_PF;
if (UART0_C1 & UART_C1_M_MASK)
*pucByte = UART0_C3; // for coherent 9 bit reads of the receiver buffer
*pucByte = UART0_D;
if (!(UART0_C1 & UART_C1_M_MASK))
if( UART_C1_PE(UART0_BASE_PTR) || ( !UART_C1_PE(UART0_BASE_PTR) && UART_C1_PT(UART0_BASE_PTR) ) )
*pucByte &= 0x7F;
UART0_C2 |= UART_C2_RIE_MASK;
return parityOK; // return TRUE if Parity Error Flag was not set
}
/* 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.
*/
/*interrupt VectorNumber_Vsci1tx void
prvvUARTTxReadyISR( void )
{
SCI1C2_TIE = FALSE;
( 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.
*/
/*interrupt VectorNumber_Vsci1rx void
prvvUARTRxISR( void )
{
SCI1C2_RIE = FALSE;
( void )pxMBFrameCBByteReceived( );
}*/
void UART0_IRQHandler (void)
{
char c = 0;
CHAR cByte;
if (UART0_S1 & UART_S1_RDRF_MASK) //Si recibio...
{
//UART0_C2 &= ~UART_C2_RIE_MASK;
( void )pxMBFrameCBByteReceived( );
if ((UART0_S1&UART_S1_TDRE_MASK)||(UART0_S1&UART_S1_TC_MASK)) //Si transmitio...
{
UART0_C2 &= ~UART_C2_TIE_MASK;
( void )pxMBFrameCBTransmitterEmpty( );
}
}
}
port.h:
#include "MKL25Z4.h"
/* Tne include fila inttypes.h is not available for HCS08, so we use our own definitions instead */
//#include <inttypes.h>
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int int16_t;
typedef unsigned short int uint16_t;
typedef signed long int int32_t;
typedef unsigned long int uint32_t;
/* Michael Barrs verification code */
#pragma MESSAGE ERROR DISABLE C1135
static union
{
char int8_t_incorrect[sizeof( int8_t ) == 1];
char uint8_t_incorrect[sizeof( uint8_t ) == 1];
char int16_t_incorrect[sizeof( int16_t ) == 2];
char uint16_t_incorrect[sizeof( uint16_t ) == 2];
char int32_t_incorrect[sizeof( int32_t ) == 4];
char uint32_t_incorrect[sizeof( uint32_t ) == 4];
};
#define INLINE
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#define memcpy (void) memcpy // gets wid of a warning in mbfuncother.c
#define ENTER_CRITICAL_SECTION( ) __asm(" CPSID i");
#define EXIT_CRITICAL_SECTION( ) __asm__("cpsie i");
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
/* The bus clock is used for computing timer and baud rate register values */
#define BM_BUS_CLOCK 24000000 // Hz
#endif
porttimer.c:
/* ----------------------- Persistent variable ------------------------------*/
static USHORT usDelta;
/* ----------------------- Start implementation -----------------------------*/
USHORT
usMBMulDiv( USHORT a, USHORT b, USHORT c )
{
ULONG x;
x = a;
x *= b;
x /= c;
return ( USHORT ) x;
}
/* Initialize Timer 1 as free running, and Channel 0 as output compare (with no pin)
*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
/* We assume 24000000 Hz bus clock and let the timer run at 1/16 of this frequency, ie. 1500000 Hz */
( void )assert( BM_BUS_CLOCK == 24000000 );
TPM1_SC = TPM_SC_CMOD(1)| TPM_SC_PS(7); //CLK dividido por 128 (24 MHz/128 = 187500 ) Para 50us necesito mod 9
//TPM1SC = 0x0F; // TOF=0,TOIE=0,CPWMS=0,CLKS=0:1,PS=1:1:1
TPM1_C1SC = TPM_CnSC_MSA_MASK;
//TPM1C0SC = 0x10; // CH0F=0,CH0IE=0,MS0=0:1,ELS0=0:0;??=0:0
/* Compute numer of timer tics corresponding to the given timeout periode */
usDelta = usMBMulDiv( usTim1Timerout50us, 900, 100 );
return TRUE;
}
/* Set the output compare register value and enable timer interrupt
*/
INLINE void
vMBPortTimersEnable( )
{
/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
TPM1_C1V = usDelta;
if (TPM1_C1SC & TPM_CnSC_CHF_MASK)
TPM1_C1SC &= ~TPM_CnSC_CHF_MASK; //TPM1C0SC_CH0F = FALSE;
TPM1_C1SC |= TPM_CnSC_CHIE_MASK; //TPM1C0SC_CH0IE = TRUE;
enable_irq (18); //Habilito la interrupcion de TPM1
}
/* Disable timer interrupts
*/
INLINE void
vMBPortTimersDisable( )
{
TPM1_C1SC &= ~TPM_CnSC_CHIE_MASK; //TPM1C0SC_CH0IE = FALSE;
}
/* Handle the interrupt and disable further timeouts
*/
TPM1_IRQHandler(void)
{
TPM1_C1SC |= TPM_CnSC_CHF_MASK; //Clear interrupt flag (CHF = 1);
TPM1_C1SC &= ~TPM_CnSC_CHIE_MASK; //TPM1C0SC_CH0IE = FALSE
( void )pxMBPortCBTimerExpired( );
}