AnsweredAssumed Answered

Issue with LPUART single-wire mode on KL17

Question asked by geoff_s on Aug 30, 2016
Latest reply on Aug 31, 2016 by geoff_s

I am developing code on a custom KL17 board, and have struck an issue with running the low-power uart in single-wire mode.

 

Most of the time my lpuart is in single-wire input mode (ie having both receiver and transmitter enabled but the Tx Pin Direction set to Input).  At regular intervals however it transmits a message by:

1. Setting the Tx Pin Direction to Output

2. Sending a packet of a few bytes with a blocking write command

3. Setting the Tx Pin Direction back to Input

 

The problem I have encountered with the above approach is that the last byte of a packet is not sent when it should, but in fact gets sent as the first byte of the subsequent packet.

 

What appears to be happening is that in step 3, the Tx pin direction change occurs immediately, before the last byte has been transmitted, so that last byte gets left in the buffer until next time the tx pin direction is set to Output.

 

Here is some sample code of what I was doing, using KSDK v2.0 calls to change the pin direction and write bytes:

outputChars[0] = 0x01u;
outputChars[1] = 0x02u;
outputChars[2] = 0x03u;
outputChars[3] = 0x04u;
// set single-wire tx pin to Output mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Output);
// write bytes
LPUART_WriteBlocking(BOOTLOADER_LPUART, outputChars, 4);
// set single-wire tx pin to Input mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Input);

 

Instead of seeing packets of bytes coming through as 0x01, 0x02, 0x03, 0x04, I see packets like 0x04, 0x01, 0x02, 0x03.  This has been confirmed independently on a logic analyser and DSO.

 

The KL17z reference manual does have this to say about TXDIR which controls the tx pin direction:

"When clearing TXDIR, the transmitter will finish receiving the current character (if any) before the receiver starts receiving data from the LPUART_TX pin".

 

Firstly, this is a confusing statement which I think is incorrect.  I believe that it should state: 

"When clearing TXDIR, the transmitter will finish transmitting the current character (if any) before the receiver starts receiving data from the LPUART_TX pin".

Secondly, my experience above suggests that the lpuart does not follow this stated behaviour.

 

TXDIR is a field in the LPUARTx_CTRL register, and the reference manual makes this comment:

"This read/write register controls various optional features of the LPUART system. This register should only be altered when the transmitter and receiver are both disabled."

Unfortunately, both the transmitter and receiver are enabled/disabled by this same register, so if you want to disable tx and rx it appears there is no choice except to alter this register anyway.

 

Nevertheless, I have tried to ensure both tx and rx were disabled before changing the tx pin direction (as shown in code below), but this has no effect - the problem remains:

// disable Rx
LPUART_EnableRx(BOOTLOADER_LPUART, false);
// set single-wire tx pin to Output mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Output);
// enable Tx
LPUART_EnableTx(BOOTLOADER_LPUART, true);
// write bytes
LPUART_WriteBlocking(BOOTLOADER_LPUART, outputChars, 4);
// disable Tx
LPUART_EnableTx(BOOTLOADER_LPUART, false);
// set single-wire tx pin to Input mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Input);
// enable Rx
LPUART_EnableRx(BOOTLOADER_LPUART, true);

 

The only method I have found that works is to explicitly wait until the last character has been sent (by checking the transmit data register empty flag) before returning the tx pin direction to Input, as shown below:

// set single-wire tx pin to Output mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Output);
// write bytes
LPUART_WriteBlocking(BOOTLOADER_LPUART, outputChars, 4);
// explicitly wait until tx data register is empty (ie last character has been sent)
// before attempting to change tx pin direction
while (!(BOOTLOADER_LPUART->STAT & LPUART_STAT_TDRE_MASK))
  {
  }
// set single-wire tx pin to Input mode
LPUART_SetTxPinDirection(BOOTLOADER_LPUART, kLPUART_TxPinDir_Input);

 

So, is this expected behaviour and the documentation is wrong ?

Or is it a hardware bug (and the documentation is still wrong) ?

Outcomes