KL03Z4 LPUART Interrupt (Newbie)

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

KL03Z4 LPUART Interrupt (Newbie)

Jump to solution
1,736 Views
beaurogers
Contributor II

This is a fairly basic question but I am fairly new to this and I have not been able to find any solution. I am trying to initilize an interrupt routine when the Receive Data Register is full for the LPUART function. My debug tests have shown that when I transmit 0x55 into pinB2, there is a detection on the rising edge (LPUART0_STAT(RXEDGIF =1)), but it never fills up the buffer (LPUART0_STAT(RDRF=0)). My register set up is seen below, am I missing something for setting up the registers or is there something else?

/////////////////////////////////////LPUART Setup///////////////////////////////////////////////////////

//setting System Integration Module//
SIM_BWR_SOPT5_LPUART0RXSRC(SIM_BASE_PTR, 0); //select LPUART_RX pin to receive data
SIM_BWR_SCGC5_LPUART0(SIM_BASE_PTR, 1);//enabling UART clock
SIM_BWR_SCGC5_PORTB(SIM_BASE_PTR, 1);//enables clock gate of Port B

///////Port Set-up///////
PORT_BWR_PCR_MUX(PORTB, 2, 0b010); //Set the Alt2 muxing on Port B, pin 2 for UART0_RX
PORT_BWR_PCR_IRQC(PORTB, 2, 0b1011);//Interrupt configuration to happen on either edge


//Setting the BAUD register//

//To achieve a baud rate of 300, we want SBR=2 [0000000000010] and OSR=4 [11111]
LPUART_BWR_BAUD_SBR(LPUART0,0b0000000010110); //Setting SBR =22
LPUART_BWR_BAUD_OSR(LPUART0, 0b00011); //OSR= x4
LPUART_BWR_BAUD_RXEDGIE(LPUART0, 1); //enabling hardware interrupts from STAT register

//setting CTRL register//
LPUART_BWR_CTRL_RIE(LPUART0, 1); //receiver data buffer full interrupt (1-enable 0-disable)
LPUART_BWR_CTRL_RE(LPUART0, 1);//enabling receiver mode
LPUART_BWR_CTRL_IDLECFG(LPUART0, 0b010);//configures 4 idle characters before an idle flag is set

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Would really appreciate it and sorry for the relative simplicity of this question. Let me know if you need any more information. 

1 Solution
1,251 Views
mjbcswitzerland
Specialist V

Hi

Here are KL03 LPUART0 initialisation and rx interrupt handling snippets from the uTasker project as reference. You can get complete code from the uTasker open source project at the links below which also enables you to simulate the complete operation to avoid complications, and accelerate learning and developments.

This shows the 48MHz IRC48M clock being used as source and configuring for 115'200 Baud.

#define SPECIAL_LPUART_CLOCK  (48000000)
KINETIS_LPUART_CONTROL lpuart_reg= uart_reg = (KINETIS_LPUART_CONTROL *)UART0_BLOCK; // select the register set for use by this channel
POWER_UP(5, SIM_SCGC5_LPUART0);           // power up LPUART 0
MCG_MC |= MCG_MC_HIRCEN;                  // ensure that the IRC48M is operating, even when the processor is not in HIRC mode
SIM_SOPT2 = ((SIM_SOPT2 & ~(SIM_SOPT2_UART0SRC_MCGIRCLK)) | (SIM_SOPT2_UART0SRC_IRC48M | SIM_SOPT2_PLLFLLSEL_IRC48M)); // select the 48MHz IRC48MHz clock as source for the LPUART
lpuart_reg->LPUART_BAUD = (((SPECIAL_UART_CLOCK/8/115200) + 1)/2); // set 115200
lpuart_reg->LPUART_CTRL = 0;              // 8 bit, no parity

_CONFIG_PERIPHERAL(B, 2, (PB_2_LPUART0_RX | UART_PULL_UPS)); // LPUART0_RX on PB2
_CONFIG_PERIPHERAL(B, 1, (PB_1_LPUART0_TX | UART_PULL_UPS)); // LPUART0_TX on PB1

fnEnterInterrupt(irq_LPUART0_ID, PRIORITY_LPUART0, _LPSCI0_Interrupt); // enter LPUART0 interrupt handler for rx and tx
lpuart_reg->LPUART_CTRL |= (LPUART_CTRL_RIE | LPUART_CTRL_RE | LPUART_CTRL_TE); // enable transmitter/receiver and rx interrupt


// LPUART 0 interrupt handler
//
static __interrupt void _LPSCI0_Interrupt(void)
{
    unsigned long ulState = LPUART0_STAT;           // status register on entry to the interrupt routine
    if (((ulState & LPUART_STAT_RDRF) & LPUART0_CTRL) != 0) {  // reception interrupt flag is set and the reception interrupt is enabled
        fnSciRxByte((unsigned char)(LPUART0_DATA), LPUART0_CH_NUMBER); // receive data interrupt - read the byte
        ulState = LPUART0_STAT;                     // update the status register
        if ((ulState & LPUART_STAT_OR) != 0) {      // if the overrun flag is set at this point it means that an overrun took place between reading the status register on entry to the interrupt and reading the data register
            (void)LPUART0_DATA;                     // read the data register in order to clear the overrun flag and allow the receiver to continue operating
        }
    }

    if (((ulState & LPUART_STAT_TDRE) & LPUART0_CTRL) != 0) {  // transmit buffer is empty and the transmit interrupt is enabled
        fnSciTxByte(LPUART0_CH_NUMBER);              // transmit data empty interrupt - write next byte, if waiting
    }
}

If you are not interested in optimal development efficiency and just in correcting your new code I believe that you have forgotten to enable clocks to the LPUART itself. See
MCG_MC |= MCG_MC_HIRCEN; // optional if the processor is already operating in HIRC mode
and
SIM_SOPT2 = ((SIM_SOPT2 & ~(SIM_SOPT2_UART0SRC_MCGIRCLK)) | (SIM_SOPT2_UART0SRC_IRC48M | SIM_SOPT2_PLLFLLSEL_IRC48M)); // without this the LPUART is in a frozen state - the edge interrupt will still operate since it is a special asynchronous interrupt but no actual LPUART functions will work yet.

Regards

Mark


http://www.utasker.com/kinetis/FRDM-KL03Z.html
http://www.utasker.com/kinetis.html

View solution in original post

8 Replies
1,251 Views
Robin_Shen
NXP TechSupport
NXP TechSupport

Hi Beau,

Would you please attached your project here, so that we can help you easier.


Don't know the 'LPUART ASYNCH Module Clock' that you selected, so I am not sure if the baudrate is well configured. But you can check the baudrate through send 0x55 and observe it by oscilloscope.

LPUART baud rate generation.png
If you select 48MHz IRC48M. To achieve a baud rate of 300, you need set SBR=0x1388 and OSR=0x1F.

I recommand you test the lpuart example in SDK_2.2_FRDM-KL03Z. You can download it refer Generating a downloadable MCUXpresso SDK v.2 package.

Best Regards,

Robin

 

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,251 Views
beaurogers
Contributor II

Yeah it works as desired and I was using 0x55 for testing. To get the 300 baud rate I used the 48Mhz internal RC clock and used SBR=4848 (1001011110000) and the OSR=32 (11111). When I send the characters through it detects them correctly. I'm not too sure where you are getting the 1388 SBR value. Using that formula with OSR=32 would suggest a baud rate of around 1048. 

0 Kudos
1,251 Views
mjbcswitzerland
Specialist V

Hi Beau

SBR = 0x1388 is correct for 300 Baud. This is 5000 and gives exactly 300.0 Baud from a 48MHz clock.
Your value of 4848 gives 309.4 Baud, which is adequate to operate (+3%) but is not absolutely correct.

Regards

Mark

0 Kudos
1,251 Views
beaurogers
Contributor II

Hi Mark,

Sorry, I am not quite seeing where the 5000 is coming from and how that gives a 300 baud rate. With the numbers I am using I am finding that my baud rate is IRC48M/(SBR*(OSR+1))=48Meg/(4848*(32+1))=300.03 baud. Is there an aspect that I am not understanding?

Regards,

Beau

0 Kudos
1,251 Views
mjbcswitzerland
Specialist V

Hi Beau

RC48M/(SBR*(OSR+1))=48Meg/(4848*(31+1))=309.41

RC48M/(SBR*(OSR+1))=48Meg/(5000*(31+1))=300.00

You were using the wrong value for OSR - is is the value in the register (0x1f = 31).

Regards

Mark

1,251 Views
beaurogers
Contributor II

Oh I see now, that makes sense. The manual describes setting the OSR register to 11111 as being 32, so that is where my confusion was. I was wondering why there was a +1 in the baud calculation. Thanks a lot Mark and Robin.

0 Kudos
1,252 Views
mjbcswitzerland
Specialist V

Hi

Here are KL03 LPUART0 initialisation and rx interrupt handling snippets from the uTasker project as reference. You can get complete code from the uTasker open source project at the links below which also enables you to simulate the complete operation to avoid complications, and accelerate learning and developments.

This shows the 48MHz IRC48M clock being used as source and configuring for 115'200 Baud.

#define SPECIAL_LPUART_CLOCK  (48000000)
KINETIS_LPUART_CONTROL lpuart_reg= uart_reg = (KINETIS_LPUART_CONTROL *)UART0_BLOCK; // select the register set for use by this channel
POWER_UP(5, SIM_SCGC5_LPUART0);           // power up LPUART 0
MCG_MC |= MCG_MC_HIRCEN;                  // ensure that the IRC48M is operating, even when the processor is not in HIRC mode
SIM_SOPT2 = ((SIM_SOPT2 & ~(SIM_SOPT2_UART0SRC_MCGIRCLK)) | (SIM_SOPT2_UART0SRC_IRC48M | SIM_SOPT2_PLLFLLSEL_IRC48M)); // select the 48MHz IRC48MHz clock as source for the LPUART
lpuart_reg->LPUART_BAUD = (((SPECIAL_UART_CLOCK/8/115200) + 1)/2); // set 115200
lpuart_reg->LPUART_CTRL = 0;              // 8 bit, no parity

_CONFIG_PERIPHERAL(B, 2, (PB_2_LPUART0_RX | UART_PULL_UPS)); // LPUART0_RX on PB2
_CONFIG_PERIPHERAL(B, 1, (PB_1_LPUART0_TX | UART_PULL_UPS)); // LPUART0_TX on PB1

fnEnterInterrupt(irq_LPUART0_ID, PRIORITY_LPUART0, _LPSCI0_Interrupt); // enter LPUART0 interrupt handler for rx and tx
lpuart_reg->LPUART_CTRL |= (LPUART_CTRL_RIE | LPUART_CTRL_RE | LPUART_CTRL_TE); // enable transmitter/receiver and rx interrupt


// LPUART 0 interrupt handler
//
static __interrupt void _LPSCI0_Interrupt(void)
{
    unsigned long ulState = LPUART0_STAT;           // status register on entry to the interrupt routine
    if (((ulState & LPUART_STAT_RDRF) & LPUART0_CTRL) != 0) {  // reception interrupt flag is set and the reception interrupt is enabled
        fnSciRxByte((unsigned char)(LPUART0_DATA), LPUART0_CH_NUMBER); // receive data interrupt - read the byte
        ulState = LPUART0_STAT;                     // update the status register
        if ((ulState & LPUART_STAT_OR) != 0) {      // if the overrun flag is set at this point it means that an overrun took place between reading the status register on entry to the interrupt and reading the data register
            (void)LPUART0_DATA;                     // read the data register in order to clear the overrun flag and allow the receiver to continue operating
        }
    }

    if (((ulState & LPUART_STAT_TDRE) & LPUART0_CTRL) != 0) {  // transmit buffer is empty and the transmit interrupt is enabled
        fnSciTxByte(LPUART0_CH_NUMBER);              // transmit data empty interrupt - write next byte, if waiting
    }
}

If you are not interested in optimal development efficiency and just in correcting your new code I believe that you have forgotten to enable clocks to the LPUART itself. See
MCG_MC |= MCG_MC_HIRCEN; // optional if the processor is already operating in HIRC mode
and
SIM_SOPT2 = ((SIM_SOPT2 & ~(SIM_SOPT2_UART0SRC_MCGIRCLK)) | (SIM_SOPT2_UART0SRC_IRC48M | SIM_SOPT2_PLLFLLSEL_IRC48M)); // without this the LPUART is in a frozen state - the edge interrupt will still operate since it is a special asynchronous interrupt but no actual LPUART functions will work yet.

Regards

Mark


http://www.utasker.com/kinetis/FRDM-KL03Z.html
http://www.utasker.com/kinetis.html

1,251 Views
beaurogers
Contributor II

Thank you very much Mark, that was indeed my problem. At the moment I am just looking to fix my code but after some proof of concept I will probably be trying to optimize it. 

0 Kudos