RTU Modbus for the Kinetis KL25Z?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

RTU Modbus for the Kinetis KL25Z?

5,075 Views
juanm
Contributor III

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(  ); }

0 Kudos
Reply
10 Replies

3,289 Views
gonzalez_carlos
Contributor I

I´m also implementing a Modbus RTU protocol on a KL25. I already have mi UART working fine. Can I apply for the free tryal of the code?

Email: gonzalez.carlosaf@gmail.com

0 Kudos
Reply

3,289 Views
evandroteixeira
Contributor II

Hi Juanm

I'm also having trouble performing the #FreeModbus #Modbus port for #FRDM-KL25Z.
Would you like to know if you have solved the problem?

0 Kudos
Reply

3,289 Views
evandroteixeira
Contributor II

my implementation of Freemodbus for FRDM-KL25Z:
GitHub - evandro-teixeira/FreeModbus_KL25Z: Port FreeModbus FRDM_KL25Z 

0 Kudos
Reply

3,289 Views
mjbcswitzerland
Specialist V

Hi

If you need a professional solution the following runs on the KL25 (master/slave/RTU/ASCII/RS232/RS485/gateway/router) and also allows MODBUS via USB.

µTasker MODBUS Extension pack

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support  / µTasker Kinetis TWR-KL25Z48M support

MODBUS (Master/Slave/Gateway/Router/RTU/ASCII/RS485/TCP/USB): µTasker MODBUS Extension pack

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

3,289 Views
juanm
Contributor III

Thanks. uTasker looks great, but sadly I can't afford it right now.

Maybe someone has ported Freemodbus to the Kinetis MCUs.

0 Kudos
Reply

3,289 Views
mjbcswitzerland
Specialist V

Hi

If you are a student or hobbyist the uTasker project is completely free, including support in this or its own forum.

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support  / µTasker Kinetis TWR-KL25Z48M support

MODBUS (Master/Slave/Gateway/Router/RTU/ASCII/RS485/TCP/USB): µTasker MODBUS Extension pack

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

3,289 Views
kigerzhang
Contributor III

Dear Mark,

 I am from Tianjin University  , how can apply a free try for Modbus software ? 

Now I am working on  a thermal controller project based on Kea . I plan to add modbus .

My email: kigerzhang@tju.edu.cn

Best Regards,

Kiger 

0 Kudos
Reply

3,289 Views
mjbcswitzerland
Specialist V

Hello Kiger

I have sent you the project at your private email address. You have already used the uTasker OpenSource project so can simply add the contents to the MODBUS folder, enable modbus in config.c and start using it.

Regards

Mark

0 Kudos
Reply

3,289 Views
oulhadjait
Contributor I

Hi Mark , hop you are doing well ? 

Please ,i want to use modbus for my project , can you please send me the free version  ? 

I am a student from Algeria university and this is my email oulhadjait@gmail.com

Thank you;

0 Kudos
Reply

3,289 Views
kigerzhang
Contributor III

Dear Mark,

Thanks a lot! I will try it.

0 Kudos
Reply