Inverted UART - trying to implement as SBUS protocol

OpenMV H7

uart.init(100000, bits=8, parity=0, stop=2, timeout_char=1000, invert=UART.INV_TX)
Gives something like err: INV_TX not found

uart.init(100000, bits=8, parity=0, stop=2, timeout_char=1000, invert=0)
Gives something like err: invert is not a argument

Note: new at python

How do invert UART (implementing SBUS protocol)

Yeah, it’s not a feature exposed in Python. The RT1062 does have this exposed in Python.

You can manually set the bit to invert the TX/RX polarities though via the stm.mem32[] operation. Import the stm module. You can also do memory access via the machine module.

See the reference manual for the STM32H743VIT6, section 48.8.3, USART control register 2 (USART_CR2).

You’ll need to compute the base address of the peripheral and then add the register offset to that base address, and then you can turn tx/rx inversion on. You’ll want to do this after initializing the peripheral in python.

stm.mem32[base_address + 0x4] = stm.mem32[base_address + 0x4] | (0x3 << 16) # TX and RX pin inversion

The base address can be found in section, 2.3.2. Scroll down until you see the USART you are controlling. Note, you need to know which UART you are setting up which will be in the constructor call to it.

Thanks for the super quick reply! Exceptional customer service!
Unfortunately, I have not yet been able to test your suggestion, as I turned my camera into a brick :slight_smile: Well … I can upload the new boot loader … but then still does not work. I’ll post a new post for this, so that the forum stays easily searchable.

I’ll get back to you on the invert UART aspect soon as I’ll be doing at least conceptual implementation today.

It’s not possible to brick the camera. Please put it into DFU mode and reupload the bootloader and firmware.

I am finding this document: https://www.st.com/en/microcontrollers-microprocessors/stm32h743vi.html

But cannot find the section you mention, nor searching for the symbol USART_CR2.
So maybe I’m looking in the wrong document?

Thx

found it: https://www.st.com/resource/en/reference_manual/dm00314099-stm32h742-stm32h743-753-and-stm32h750-value-line-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

It took me a while to find it, because I’m not that familiar with these type of documents …
But so I think it’s: 0x40004400

Yep, that’s the base for USART2.

However, it could also be UART2. These are different devices.

I need to use UART2? (Because I soldered my leads on UART1)

0x40011400 - 0x400117FF USART6 Section 48.8: USART registers
0x40011000 - 0x400113FF USART1 Section 48.8: USART registers
0x40005000 - 0x400053FF UART5 Section 48.8: USART registers
0x40004C00 - 0x40004FFF UART4 Section 48.8: USART registers
0x40004800 - 0x40004BFF USART3 Section 48.8: USART registers
0x40004400 - 0x400047FF USART2 Section 48.8: USART registers
0x40007C00 - 0x40007FFF UART8 Section 48.8: USART registers
0x40007800 - 0x40007BFF UART7 Section 48.8: USART registers

I found this in the docs … unscambled we get:

0x40011000 - 0x400113FF USART1 Section 48.8: USART registers
0x40004400 - 0x400047FF USART2 Section 48.8: USART registers
0x40004800 - 0x40004BFF USART3 Section 48.8: USART registers
0x40004C00 - 0x40004FFF UART4 Section 48.8: USART registers
0x40005000 - 0x400053FF UART5 Section 48.8: USART registers
0x40011400 - 0x400117FF USART6 Section 48.8: USART registers
0x40007800 - 0x40007BFF UART7 Section 48.8: USART registers
0x40007C00 - 0x40007FFF UART8 Section 48.8: USART registers

Can you provide some clarity on how these connect to the pins on OpenMV cam?

Hi Nick,

USART_CR2 is a register in the specific UART. It’s not the UART peripheral itself.

The particular UART you are using is based on the number you passed to pyb.UART() when you were constructing the object. I don’t know if its the USART1 or UART1. One of them if you try to modify won’t work and will probably crash the system. So, don’t save the script to the OpenMV Cam until you figure out which one. If the peripheral is not initialized, then writing to its register space will cause a processor exception, leading to a system reset.

Anyway, just try both and one should work (talking about the USART or UART base address).

It looks like there’s only USART1. So, try that base address.

Hi Kwagyeman,

Thank you for your help so far!
I am getting closer in the SBus protocol …
I should not have started from the existing code, I found online … because I believe it is fundamentally flawed.

They do not take into consideration that the package come in burst:
3 ms data, 6 ms silence, 3 ms data, 6 ms silence …

And this is the primary way of finding the start and end of a package (not scanning for package HEADER or FOOTER in the concatinated stream of data, which does not take into account timing).

All that is needed, is an interrupt or timer, that listens for ‘silence’ on the uart rx.

        ...
        poll_data_bound = partial_method(self.poll_data, self)
        timProve = pyb.Timer(2)
        timProve.init(period=1, callback=poll_data_bound)  # every 1ms
        ...

    def poll_data(self): # must be called every 1 millisecond
        if self.uart.any() > 0:
            self.readBytes += self.uart.read()
            self.last_frame_received_ticks_ms = time.ticks_ms()
            if self.readBytes[0] == 0x0F and self.readBytes[24] == 0x00:
                self.lastFrame = self.readBytes
                self.readBytes = bytearray()
        if self.last_frame_received_ticks_ms is None or time.ticks_diff(time.time_ms(), self.last_frame_received_ticks_ms) > 3:
            # Clear buffer if no data received for 3 ms
            # SBUS is expected to come in frames, and then silence
            # 3ms of data, 6ms of silence, 3ms of data, 6ms of silence, ...
            self.readBytes = bytearray()

full code: OpenMV/all_in_one_file.py at 6533425f4f1e75ca7f020e2054b620e2b25603c9 · nickreyntjens/OpenMV · GitHub

timing details (protocol spec - easy): OpenMV/all_in_one_file.py at 6533425f4f1e75ca7f020e2054b620e2b25603c9 · nickreyntjens/OpenMV · GitHub

Am I allowed to do a ‘heavy’ operation, such as reading uart, or dynamically, allocating structures in a timer or interupt call back? Is my approach acceptable way, to use the timing information on the bus?

Kr,
Nick

You can’t allocate memory in timer callbacks. You are allowed to read data from the UART through and write it to a buffer. As long as you don’t create any new objects you are fine.

So, the setting the readBytes to bytearray() is something you’d want to avoid as this is clearing an object. Maybe instead use a variable to signal state like a length variable. Also, keep the readBytes array fixed in size. You can use readInto or just manual set bytes in it to avoid any memory allocations.

The reason for not being able to allocate memory is that the heap isn’t reentrant. The timer callback is an interrupt.

Note, you can schedule callbacks from inside interrupts: micropython – access and control MicroPython internals — MicroPython 1.22 documentation (openmv.io)

This allows you to bypass the issue.