2

I'm using a PIC16F18326 to transmit some data over UART (asynchronous, 250k baud rate). The MCU runs at 32MHz, with an actual instruction frequency of 8MHz.

I'm using the following assembly code to send 4 bytes (from 0xAA to 0xAD - don't mind the useless repeated BANKMASK):

movlw   0xAA
banksel TX1REG
movwf   BANKMASK(TX1REG)
movlw   0xAB
banksel TX1REG
movwf   BANKMASK(TX1REG)
movlw   0xAC
banksel TX1REG
movwf   BANKMASK(TX1REG)
movlw   0xAD
banksel TX1REG
movwf   BANKMASK(TX1REG)
goto $

The result from the logic analyzer is that only 0xAA and 0xAD have been sent (first and last byte).

I know that I can't send 4 bytes back-to-back (without any delay, or some checks of the UART registers), but I would have expected to send 0xAA and 0xAB (the first 2 bytes).

According to the datasheet, if TX1REG and TSR registers are empty (which is my case since I have never transmitted anything), I can write to TX1REG to start the send of the first byte, and then after at least 1 clock cycle I can queue up the second byte. According to the code below, there are 3 clock cycles between the 2 writes.

So, what is going wrong?

HBv6
  • 3,487
  • 4
  • 30
  • 43
  • "After at least 1 clock cycle"... This is probably referring to UART clock cycles, which may be far longer than CPU clock cycles. Probably you are writing the second byte before the UART has transferred the data out of TX1REG into TSR. UARTs typically use a 16× clock, so the UART clock in your case may be 4 MHz, which would explain why TX1REG is finally empty by the fourth write. – prl Mar 15 '19 at 02:00
  • @prl The datasheet says "Tcy", where Tcy is the instruction time. – HBv6 Mar 15 '19 at 06:26

2 Answers2

4

Have a look at page 367 of this about the list of features:

  • Full-duplex asynchronous transmit and receive
  • Two-character input buffer
  • One-character output buffer
  • Programmable 8-bit or 9-bit character length
  • Address detection in 9-bit mode
  • Input buffer overrun error detection
  • Received character framing error detection
  • (etc.)

The problem you are experiencing acts just like a buffer overrun. If this is about the correct USART, then you are getting just would be expected.

A more general purpose bit of software would be useful to loop for each character and await the "buffer ready bit" (or whatever it is called) before loading the buffer with the next character.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • I don't believe it's a buffer overrun for 2 reasons: as you stated, the UART supports two-character input buffer; see page 371 where the back-to-back transmission happens. – HBv6 Mar 14 '19 at 19:07
  • @HBv6: But aren't you using the output direction? – wallyk Mar 14 '19 at 19:16
  • You are right, I misinterpreted that... But I think that page 371 still stands? – HBv6 Mar 14 '19 at 19:29
1

Found the reason. Writing to TX1REG overwrites whatever the register contains. The write goes through independently on any status bit (TXIF in this case).
When the UART is ready to transmit, it will just fetch the TX1REG content and send it.

In my example of above:

Write 0xAA
0xAA is sent immediately
Write 0xAB
0xAB is stored, but not sent because the first send has not finished yet
Write 0xAC
0xAC is stored, but not sent because the first send has not finished yet
Write 0xAD
0xAD is stored, but not sent because the first send has not finished yet

After a while the transmission of 0xAA finishes, and at this point the UART sends 0xAD because it is the (last) content of TX1REG.

HBv6
  • 3,487
  • 4
  • 30
  • 43
  • Glad you understand the problem. How is that different than my answer? – wallyk Mar 15 '19 at 13:54
  • @wallyk I think I was over-stressed and didn't completely understand your answer (especially the buffer overrun). Sorry, I approved your answer as best solution. – HBv6 Mar 15 '19 at 15:29
  • Thanks! You didn't seem stressed, but happy that is over. Sometimes thinking about what might *cause* a problem is more productive than gathering more information. FWIW. – wallyk Mar 15 '19 at 15:55