Request to use KL03 I/O to implement software UART similar sample code

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

Request to use KL03 I/O to implement software UART similar sample code

809 Views
tigerlo
Contributor III

Hi,

    I want to use KL03 I/O to implement software UART (full duplex, baud rate :9600/19200/38400), are there any similar sample code/document  that I can reference  ?

Thanks.

Tiger Lo

0 Kudos
4 Replies

621 Views
tigerlo
Contributor III

Earl,

    Thanks for your help, I start from here. are there KL0X series software uart code ?

    Best Regard.

Tiger

0 Kudos

621 Views
egoodii
Senior Contributor III

I am not intimately familiar with the timer hardware of the KL series --- I come from the S08 TPM, which by extension means also the 'K' series TPM turned FTM.

Edit:

A light perusal of the KL03 RM indicates the 'same' basic TPM in use, so that linked TX code-fragment should be a fine basis (with your own TX-buffer handling, of course) --- it will take me a little time to dig up my RX state machine.

621 Views
tigerlo
Contributor III

Earl,

    Thanks, I start from here.

Tiger

0 Kudos

621 Views
egoodii
Senior Contributor III

The way to run a 'software driven UART" is actually a timer-banged function.  You set a timer to free-run (full modulo) and dedicate two channels, one to RX and one to TX.  TX is 'simple enough', you just create timer-channel-event-edges spaced at your bit-rate, loading each 'next bit edge event' at the interrupt indicating the 'previous' event has been 'handled'.  An example TX is here:

Can we Change FTM Mod value Simultaneously 

RX is a bit trickier, and also a little less 'precise'.  You set the RX pin as falling-edge-triggered capture input, and this detection is your presumed initiation of 'start bit'.  You re-set this 'receive' timer channel to interrupt you in 'a bit less than 1/2 bit-time', and at that point you sample the GPIO to 'confirm' start bit, and you continue to set the timer-interrupt one bit-time apart after that for the rest of the byte and stop-bit(s).  You set that first interval a 'little less than 1/2' because you have to 'fudge' for the time to get from the actual falling-edge into the timer-start of that interrupt handler, and also consider the time from timer-edge to get to THAT handlers actual 'input sample point'.  This 'fudge factor' (and the general considerations of variable interrupt response time providing jitter on your GPIO sample-point) lead to the 'less accuracy' in RX bit timing.

The following S08 code is 'particularly limited' (but functional in its context), in that it receives ONLY 8N(1) format, and does NO error checking of any kind, not even the aforementioned 'start bit verify' (instead skipping right to the center of the first data-bit, 1.4 bit-times away):

enum SIState {SI_Idle, SI_Rcvng} SI1_State = SI_Idle;

//Timer-banged serial input/output w/timer1:3&5 for communication to DUT
#define BAUDRATE1 (1000000/9600)       //uS per bit
#define BAUDWIDS (u16_t)(1.4*1000000/9600) //Clks from start-edge to first-bit center-sample
                            //Set a little early to allow for potential latency

//#define INT_Watch
//Event handler for timer-banged serial input on TPM1C35
ISR( SOFT_UART1_RX )
{
    static u8_t SI1byte, SI1_bit_cnt;
#ifdef INT_Watch
    PTFD_PTFD5 = 1;
#endif
    (void)TPM1C5SC;                             //Part of two-step interrupt reset, read first
    clrReg8Bits(TPM1C5SC, 0x80);          // Reset compare-interrupt-request flag
    if( SI1_State == SI_Rcvng )
    {                                             //Sample input
        if( PTDD_PTDD7 )
            SI1byte |= 0x80;                      //Add in '1' bits
        if( --SI1_bit_cnt == 0 )                  //Done?
        {
            setReg8(TPM1C5SC, 0x48);            //Back to falling edges for next 'start' bit
            (void)TPM1C5SC;                     //Another interrupt reset, due to mode change
            clrReg8Bits(TPM1C5SC, 0x80);  // Reset compare-interrupt-request flag
            SI1_State = SI_Idle;
            DUT_RCVBuf[DUT_RCVbufIN] = SI1byte;
            DUT_RCVbufIN++;                       //Simple circular 'in' buffer
            DUT_RCVbufIN &= DUTrxBUFsize-1;
        }else                                     //More bits to come
        {
            SI1byte >>= 1;                        //Shift toward LSB
            setReg16(TPM1C5V, TPM1C5V+BAUDRATE1); // Compare 1-bittime value for next bit
        }
    }else if( SI1_State == SI_Idle )      //Falling edge (start bit) found, prepare for real bits
    { u16_t temp;
        setReg8(TPM1C5SC, 0x50);                //Just periodic interrupts from here
        temp = TPM1C5V+BAUDWIDS/2;            //Keep the additions <128 for better S08 opcodes!
        setReg16(TPM1C5V, temp+BAUDWIDS/2);   // 1.4x Compare 1-bittime value for first bit center
//        (void)TPM1C5SC;                         //Another interrupt reset, due to mode change
//        clrReg8Bits(TPM1C5SC, 0x80);      // Reset compare-interrupt-request flag
//Latest TPM module, later writes to SC would cancel CNTR write!!!!!!!!
        SI1_State = SI_Rcvng;
        SI1byte = 0;
        SI1_bit_cnt = 8;
    }
#ifdef INT_Watch
    PTFD_PTFD5 = 0;
#endif
}

AN2502 goes into more specific detail.

0 Kudos