Output to UART1 KL25Z

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

Output to UART1 KL25Z

Jump to solution
3,406 Views
gbd
Contributor II

Hello everyone,

I'm trying to figure out how to get output from UART1 on my KL25Z. I'm using a bare metal platform and not CW. I've got a uart1_init() to configure the registers and everything looks to be correct but I'm not getting any output. This exact same init script will allow me to move uart0 around to the different uart0 pin locations. Any help you'd be willing to provide would be greatly appreciated

void uart1_init(int baud_rate)

{

    SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;

    // Turn on clock to UART1 module and select 48Mhz clock (FLL/PLL source)

    SIM_SCGC4 |= SIM_SCGC4_UART1_MASK;

    SIM_SOPT5 &= ~SIM_SOPT5_UART1TXSRC_MASK;

    SIM_SOPT5 |= SIM_SOPT5_UART1TXSRC(0);                 // FLL/PLL source

    // Select "Alt 3" usage to enable UART1 on pins

    PORTC_PCR3 = PORT_PCR_MUX(3);

    PORTC_PCR4 = PORT_PCR_MUX(3);

    UART1_C2 = 0;

    UART1_C1 = 0;

    UART1_C3 = 0;

    UART1_C4 = 0;

    UART1_S2 = 0;

    // Set the baud rate divisor

    #define OVER_SAMPLE 16

    uint16_t divisor = (CORE_CLOCK / OVER_SAMPLE) / baud_rate;

    UART1_C4 = UARTLP_C4_OSR(OVER_SAMPLE - 1);

    UART1_BDH = (divisor >> 8) & UARTLP_BDH_SBR_MASK;

    UART1_BDL = (divisor & UARTLP_BDL_SBR_MASK);

    // Initialize transmit and receive circular buffers

    buf_reset(tx_buffer1, BUFLEN);

    buf_reset(rx_buffer1, BUFLEN);

    // Enable the transmitter, receiver, and receive interrupts

    UART1_C2 = UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK;

    printf("UART1_C4 = %x \r\n", UART1_C4);

    printf("UART1_C2 = %x \r\n", UART1_C2);

    enable_irq(INT_UART1);

}

int uart1_write_err(char *p, int len)

{

    int i;

    __disable_irq();

    for(i=0; i<len; i++) {

        while((UART1_S1 & UART_S1_TDRE_MASK) == 0)  // Wait until transmit buffer empty

            ;

        UART1_D = *p++;                     // Send char

    }

    __enable_irq();

    return len;

}

Tags (2)
1 Solution
1,126 Views
gbd
Contributor II

Martyn,

Thanks for your help! I figured out the issue, I was initializing the UART with the core clock (48Mhz) vs the bus clock (28Mhz). I'm going to post a clean, working solution for folks trying to accomplish the same thing in the future.

Thanks  again,

Greg

View solution in original post

8 Replies
1,126 Views
gbd
Contributor II

Sorry,

I copied the wrong function, here is my uart1_write()

int uart1_write(char *p, int len)

{

    int i;

    for(i=0; i<len; i++) {

        while(buf_isfull(tx_buffer1))        // Spin wait while full

            ;

        buf_put_byte(tx_buffer1, *p++);

        UART1_C2 |= UART_C2_TIE_MASK;           // Turn on Tx interrupts

    }

    return len;

}

0 Kudos
1,126 Views
martynhunt
NXP Employee
NXP Employee

Hi,

UART0 on the KL25 differs from UART1. I would check the reference manual to make sure you are setting the registers correctly for UART1. See Reference Manual Chapter 40.

Also, you need to subtract 16 from INT_UART1 in enable_irq(). For example:

enable_irq(INT_UART1 - 16);

You need to provide enable_irq() with the IRQ number (NVIC interrupt source number), which is the Vector number minus 16. See Reference Manual section 3.3.2.3.

Hope this helps you. Let me know if it does or not. Thank you.

Best regards,

Martyn

0 Kudos
1,126 Views
gbd
Contributor II

Martyn,

Thanks for the advice. I am shifting my irq to the left 16.

// Interrupt enabling and disabling

static inline void enable_irq(int n) {

    NVIC_ICPR |= 1 << (n - 16);

    NVIC_ISER |= 1 << (n - 16);

}

Do you see anything that is missing from this setup? My C1, C2, C3, C4 and S2 register seem to have the correct values. Any other ideas?

void uart1_init(int baud_rate)

{

    SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;

    printf("SIM_SOPT5 = %x \r\n", SIM_SOPT5);

    // Turn on clock to UART1 module and select 48Mhz clock (FLL/PLL source)

    SIM_SCGC4 |= SIM_SCGC4_UART1_MASK;

    printf("SIM_SCGC4 = %x \r\n", SIM_SCGC4);

    SIM_SOPT5 &= ~SIM_SOPT5_UART1TXSRC_MASK;

    printf("SIM_SOPT5 = %x \r\n", SIM_SOPT5);

    SIM_SOPT5 |= SIM_SOPT5_UART1TXSRC(0);                 // FLL/PLL source

    printf("SIM_SOPT5 = %x \r\n", SIM_SOPT5);

    // Select "Alt 3" usage to enable UART1 on pins

    PORTC_PCR3 = PORT_PCR_MUX(3);

    PORTC_PCR4 = PORT_PCR_MUX(3);

    UART1_C2 = 0;

    UART1_C1 = 0;

    UART1_C3 = 0;

    UART1_C4 = 0;

    UART1_S2 = 0;

    // Set the baud rate divisor

    #define OVER_SAMPLE 16

    uint16_t divisor = (CORE_CLOCK / OVER_SAMPLE) / baud_rate;

    UART1_C4 = UARTLP_C4_OSR(OVER_SAMPLE - 1);

    UART1_BDH = (divisor >> 8) & UARTLP_BDH_SBR_MASK;

    UART1_BDL = (divisor & UARTLP_BDL_SBR_MASK);

    // Enable the transmitter, receiver, and receive interrupts

    UART1_C2 = UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK;

    enable_irq(INT_UART1);

}

// A blocking write, useful for error/crash/debug reporting

int uart1_write_err(char *p, int len)

{

    int i;

    __disable_irq();

    for(i=0; i<len; i++) {

        while((UART1_S1 & UART_S1_TDRE_MASK) == 0);  // Wait until transmit buffer empty       

        UART1_D = *p++;                     // Send char

        }

    __enable_irq();

    return len;

}

main() {

    int len = 0;

    char *pyld;

    pyld = (char *) malloc(39);

    memset(pyld, 0, sizeof(pyld));

     ... build pyld ...

     uart1_write_err(pyld, strlen(pyld));

}

Thanks,
Greg

0 Kudos
1,126 Views
gbd
Contributor II

If I remove my baud rate settings I can get a dip in the uart1 signal (i can see when hooked up the o-scope). The other think I notice is that it doesn't seem to come out of the "while((UART1_S1 & UART_S1_TDRE_MASK) == 0);  // Wait until transmit buffer empty" loop.

0 Kudos
1,127 Views
gbd
Contributor II

Martyn,

Thanks for your help! I figured out the issue, I was initializing the UART with the core clock (48Mhz) vs the bus clock (28Mhz). I'm going to post a clean, working solution for folks trying to accomplish the same thing in the future.

Thanks  again,

Greg

1,126 Views
gordonjess
Contributor I

Hi Greg,

I am trying to accomplish the same thing with UART2, you got that code handy by any chance?  I was also confused by the differences in control registers between UART0 and UART1/UART2.

0 Kudos
1,126 Views
martynhunt
NXP Employee
NXP Employee

Hi Greg,

UART1s baud rate is generated differently from UART0s. Section 40.3.1 of the reference manual explains how the baud rate is generated. It is:

Baud Rate = (UART Module Clock) / (BR x 16)

or

uint16_t divisor = CORE_CLOCK / (baud_rate * 16);

BR is defined by setting the Baud Rate Modulo Divisor. UART1 does not have OSR bits to set. BR is defined by setting the 13 bits of SBR found in UART1_BDH  and UART1_BDL.

So this line,

UART1_C4 = UARTLP_C4_OSR(OVER_SAMPLE -1);

will not set an OSR value for UART1,

I would also enable UART1 interrupts in the uart1_init function. Then use your interrupt handler to clear the flags after an interrupt occurs by reading UART1_S1. Can you get output on UART1 when not using interrupts?

Would it be possible to attach your code in order for me to test it? Also, what is the name of the CPU header file are you using?

Thank you,

Martyn

0 Kudos
1,126 Views
gbd
Contributor II

Martin,

Here's a tar file with all the code I'm working with. It includes the header file. I really appreciate your help!

BTW, this code is pretty dirty but I'm sure you can figure out what's going on easily.

Thanks,

Greg

0 Kudos