Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RP2040: Support for UART #4224

Merged
merged 7 commits into from
Feb 26, 2021
Merged

RP2040: Support for UART #4224

merged 7 commits into from
Feb 26, 2021

Conversation

microdev1
Copy link
Collaborator

No description provided.

@jerryneedell
Copy link
Collaborator

jerryneedell commented Feb 19, 2021

Tested by connecting a gps Breakout to TX0/RX0 on Pins GP12/13 and running the gps_echotest.py script. worked normally.
Edited to add -- gps_echotest works ok, but gps_simpletest is not working -- looking into it.

@ladyada
Copy link
Member

ladyada commented Feb 19, 2021

oh wow, this is awesome. let me try it too :)

@ladyada
Copy link
Member

ladyada commented Feb 19, 2021

ok GPS tested, 9600 baud and works as expected. will try some RX/TX loopback tests

@ladyada
Copy link
Member

ladyada commented Feb 19, 2021

tested all common baud rates from 1200 to 115200 with

import time
import board
import busio

uart = busio.UART(board.TX, board.RX, baudrate=115200, timeout=0.1)

char = 0
while True:
    uart.write(bytearray([char]))
    char = (char + 1) % 256
    data = uart.read(1) 
    print(data)  # this is a bytearray type

@ladyada ladyada mentioned this pull request Feb 19, 2021
@jerryneedell
Copy link
Collaborator

@ladyada Did gps_simpletest work for you? It is not seeing a fix for me.... echotest works fine.....

@ladyada
Copy link
Member

ladyada commented Feb 19, 2021

i didnt test fix cause thats a 'sit it outdoors' thing and its really cold out :D

@jerryneedell
Copy link
Collaborator

hopefully not related to UART -- trying to figure it out....

@jerryneedell
Copy link
Collaborator

jerryneedell commented Feb 19, 2021

There may be an issue -- the gps.update is faiong in _read_sentence here:

    def _read_sentence(self):
        # Parse any NMEA sentence that is available.
        # pylint: disable=len-as-condition
        # This needs to be refactored when it can be tested.

        # Only continue if we have at least 32 bytes in the input buffer
        print(self.in_waiting)        
        if self.in_waiting < 32:
            return None

https://github.com/adafruit/Adafruit_CircuitPython_GPS/blob/master/adafruit_gps.py#L200
self.in_waiting seems to be 1 all the time

@jerryneedell
Copy link
Collaborator

is there potentially an issue with this not returning the correct value for bytes in the uart?

return uart_is_readable(self->uart);

@microdev1
Copy link
Collaborator Author

Thanks! @ladyada and @jerryneedell for the extensive testing... 👍

is there potentially an issue with this not returning the correct value for bytes in the uart?

Seems like uart_is_writable can only return if data is available or not and not the actual number of bytes.

/*! \brief Determine whether data is waiting in the RX FIFO
 *  \ingroup hardware_uart
 *
 * \param uart UART instance. \ref uart0 or \ref uart1
 * \return 0 if no data available, otherwise the number of bytes, at least, that can be read
 *
 * \note HW limitations mean this function will return either 0 or 1.
 */
static inline bool uart_is_readable(uart_inst_t *uart) {
    // PL011 doesn't expose levels directly, so return values are only 0 or 1
    return !(uart_get_hw(uart)->fr & UART_UARTFR_RXFE_BITS);
}

@ladyada
Copy link
Member

ladyada commented Feb 19, 2021

yeha we should be buffering the UART data internally

@microdev1
Copy link
Collaborator Author

yeha we should be buffering the UART data internally

yup... that's what I was thinking for a workaround

@jerryneedell
Copy link
Collaborator

just "for fun" I changed the gps code to continue as long as anything was in the UART and now both the gps_simpltest.py and gps_time_source.py examples work.
This is what I changed at https://github.com/adafruit/Adafruit_CircuitPython_GPS/blob/master/adafruit_gps.py#L200

        #if self.in_waiting < 32:
        if not self.in_waiting:
            return None

Not a fix, but it's nice to see it running

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this! I think we do need to add buffering before we merge this because the API explicitly allows setting the buffer size.

We can either copy other ports and use an interrupt to write into a ring buffer. Or, we can use the RP2040 ring DMA while constraining the buffer sizes to powers of two.

I'd be happy to add the buffering next week if you'd like to hand it off.

ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.h Outdated Show resolved Hide resolved
shared-bindings/busio/UART.c Outdated Show resolved Hide resolved
@microdev1 microdev1 requested a review from tannewt February 23, 2021 18:34
@microdev1
Copy link
Collaborator Author

the API explicitly allows setting the buffer size

I see. I have added internal buffering now.
@jerryneedell can you do a retest of gps_simpletest.

@jerryneedell
Copy link
Collaborator

@microdev - sorry... It does not work at all. Even the "echotest" now just returns a steady stream of "HHHHHHH" characters. the "simpletest" crashes due to a memory allocation error.....

@jerryneedell
Copy link
Collaborator

jerryneedell commented Feb 23, 2021

did a simple test -- with nothing connected -- same result with GPS connected.

Adafruit CircuitPython 6.2.0-beta.2-48-gefe6aab5f on 2021-02-23; Raspberry Pi Pico with rp2040
>>> import time
>>> import board
>>> import busio
>>> 
>>> uart = busio.UART(board.GP12, board.GP13, baudrate=9600, timeout=10)
>>> 
>>> uart.in_waiting
235
>>> uart.read(1)
b'H'
>>> uart.read(1)
b'H'
>>> uart.in_waiting
235
>>> 

@jerryneedell
Copy link
Collaborator

FYI _ I built CP with this PR and tested it with the GPS -- both the echotest and simpletest now work normally.

- add internal buffering
- rtc initialization fix
@tannewt tannewt added enhancement rp2040 Raspberry Pi RP2040 labels Feb 24, 2021
@ajs256
Copy link

ajs256 commented Feb 24, 2021

Tested using:

import board
import busio
import random

uart = busio.UART(board.GP0, None, baudrate=9600)

uart.write("|-".encode("UTF-8")) # Clear display

uart.write("Hello world!    ".encode("UTF-8")) # Show some text.

uart.write("Rand: ".encode("UTF-8")) 
rand = str(random.randint(0, 100))
uart.write(rand.encode("UTF-8")) # So I can see that it's working every time, print a random number.

and a SparkFun Serial LCD. I can verify that it is reliably writing, and that the random value is different every time.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the improvements. Unfortunately, UART has a lot of corner cases. Let me know if you'd like to hand off the PR to me.

ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
ports/raspberrypi/common-hal/busio/UART.c Outdated Show resolved Hide resolved
@lesamouraipourpre
Copy link

just "for fun" I changed the gps code to continue as long as anything was in the UART and now both the gps_simpltest.py and gps_time_source.py examples work.
This is what I changed at https://github.com/adafruit/Adafruit_CircuitPython_GPS/blob/master/adafruit_gps.py#L200

        #if self.in_waiting < 32:
        if not self.in_waiting:
            return None

Not a fix, but it's nice to see it running

As an aside the 32 is too large, new issue is #56. I'll do a PR for it, once my previous PR gets past PyLint and the examples duplicate-code annoyance.

@microdev1 microdev1 linked an issue Feb 25, 2021 that may be closed by this pull request
@microdev1
Copy link
Collaborator Author

Unfortunately, UART has a lot of corner cases. Let me know if you'd like to hand off the PR to me.

@tannewt Thanks! for the review. I have addressed the current set of suggestions.
If there is still a chance of improvement you can go ahead push directly to my branch. :)

- address suggested changes
- refine uart instance availibility checks
- improve pin validation and rx buffer handling
* Always clear the peripheral interrupt so we don't hang when full
* Store the ringbuf in the object so it gets collected when we're alive
* Make UART objects have a finaliser so they are deinit when their
  memory is freed
* Copy bytes into the ringbuf from the FIFO after we read to ensure
  the interrupt is enabled ASAP
* Copy bytes into the ringbuf from the FIFO before measuring our
  rx available because the interrupt is based on a threshold (not
  > 0). For example, a single byte won't trigger an interrupt.
@tannewt
Copy link
Member

tannewt commented Feb 26, 2021

Ok, I've fixed a couple more issues I spotted. If folks could test and review, that'd be awesome.

@jerryneedell
Copy link
Collaborator

Ok, I've fixed a couple more issues I spotted. If folks could test and review, that'd be awesome.

Reran gsp_echotest and gps_simpletest -- both still work normally.

@tannewt
Copy link
Member

tannewt commented Feb 26, 2021

Gah, I had my debug text files in there for a bit. re-did that last commit and the CI needs to run again.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @microdev1

@tannewt tannewt merged commit 888a0c5 into adafruit:main Feb 26, 2021
@microdev1 microdev1 deleted the busio-uart-rp branch February 27, 2021 18:48
@microdev1
Copy link
Collaborator Author

Thanks! everyone for collaborating on this. 👍

@ladyada
Copy link
Member

ladyada commented Feb 27, 2021

Thank you for working hard on the PR, its a wonderful and helpful addition!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement rp2040 Raspberry Pi RP2040
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement busio.UART
6 participants