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( ); }
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
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?
my implementation of Freemodbus for FRDM-KL25Z:
GitHub - evandro-teixeira/FreeModbus_KL25Z: Port FreeModbus FRDM_KL25Z
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.
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
Thanks. uTasker looks great, but sadly I can't afford it right now.
Maybe someone has ported Freemodbus to the Kinetis MCUs.
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
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
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
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;
Dear Mark,
Thanks a lot! I will try it.