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;
}
解決済! 解決策の投稿を見る。
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
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;
}
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
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
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.
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
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.
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