-
Notifications
You must be signed in to change notification settings - Fork 18.2k
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
Add support for running IOMCU FW on CubeRedSecondary #29094
base: master
Are you sure you want to change the base?
Conversation
ed65847
to
2647c5d
Compare
dfc80b2
to
100901b
Compare
0a9b94d
to
78d8f69
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good. Some small changes. Think you need to think about how it looks if someone adds F4 support (which has been requested)
libraries/AP_IOMCU/fw_uploader.cpp
Outdated
@@ -281,7 +290,7 @@ bool AP_IOMCU::erase() | |||
debug("erase..."); | |||
send(PROTO_CHIP_ERASE); | |||
send(PROTO_EOC); | |||
return get_sync(10000); | |||
return get_sync(20000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a timeout? Maybe add a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); | ||
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | ||
#if defined(STM32H7) | ||
| (1<<20) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs a define
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will leave a comment, we don't have a standard define for this as this is from an errata
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed through define and also in UARTDriver
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); | ||
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | ||
#if defined(STM32H7) | ||
| (1<<20) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
uart->usart->CR1 = cr1 | USART_CR1_SBK; | ||
|
||
CLEAR_ISR_FLAG(LBD); | ||
SEND_BREAK(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a slight change in behaviour because this was a local variable for threading reasons. Ideally would preserve the current semantics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am going to change it back to original as it doesn't really matter in this context.
But the change is actually correct. Firstly a thread cannot interrupt an interrupt, another higher priority interrupt can. Secondly, only bit we want to set in CR1 is Line Break, rest of the bits we don't want to touch. With the older method there's a chance we can end up doing just that.
Basically if there was another interrupt or peripheral event (between where we store cr1 and call SEND_BREAK) where the CR1 is changed we will end up changing it again unknowingly. Fortuntely we don't mess with CR1 outside of init and this interrupt, so it is a non-issue. But in general this can cause issue.
@@ -176,7 +257,7 @@ static void idle_rx_handler(hal_uart_driver *uart) | |||
|
|||
if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) { | |||
/* TC interrupt cleared and disabled.*/ | |||
uart->usart->SR &= ~USART_SR_TC; | |||
CLEAR_ISR_FLAG(TC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better to use the MODIFY_REG() macro that you used in bdshot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't work, here. Its a completely different operation for STM32H7. its a modify register operation in STM32F1 but a simple write operation in H7. So this is the only way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
uart->dmatx = dmaStreamAllocI(STM32_UART_USART2_TX_DMA_STREAM, | ||
STM32_UART_USART2_IRQ_PRIORITY, | ||
uart->dmatx = dmaStreamAllocI(HAL_IO_FMU_COMMS_TX_DMA_STREAM, | ||
12, //IRQ Priority |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is bypassing the config, thing it should use the define or put a define above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I was trying to avoid adding yet another define that's going to remain untouched. Will add this to define as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still pending?
@@ -447,7 +567,7 @@ void AP_IOMCU_FW::update() | |||
loop_counter++; | |||
|
|||
if (do_reboot && (last_ms > reboot_time)) { | |||
hal.scheduler->reboot(true); | |||
hal.scheduler->reboot(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was incorrect to begin with. We don't actually want to hold in bootloader here. And we don't for iomcu bootloader we are currently using (as its extremely old and didn't even have that feature).
The behaviour of this in current bootloader is that it holds the MCU in bootloader forever. If you reboot ardupilot, the iomcu will sit in bootloader forever, hence failing IOMCU sanity check and force trigger a firmware update everytime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok sounds reasonable. Probably needs testing on other boards that have iofirmware update issues - particularly Pixhawk6X
5fad99f
to
18c7ecc
Compare
18c7ecc
to
d8a852b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just needs testing iofirmware upgrades on some of the other boards (e.g. Pixhawk6X)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm glad to see this becoming an option, just need to work out how to properly dynamically choose if UART is IOMCU or some other protocol, the method in this PR doesn't look right
also, this does change the size of iofirmware_f103_lowpolh.bin by 8 bytes, need to work out why
@@ -1884,6 +1884,12 @@ void usb_initialise(void) | |||
// disable TX/RX pins for unusued uart | |||
void UARTDriver::disable_rxtx(void) const | |||
{ | |||
#if HAL_WITH_IO_MCU | |||
if (sdef.get_index() == HAL_UART_IOMCU_IDX) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this added? it would be valid to call this function on IOMCU uart if BRD_IO_ENABLE was false for example. We don't do that now, but I don't understand the special case
I suspect this is all about the serial port being able to be either a link to IOMCU or a normal serial manager uart (eg. for PPP of mavlink)
why not add a SERIALn_PROTOCOL=IOMCU enum value, then handle this in SerialManager?
@@ -87,6 +87,12 @@ int main(void) | |||
bool try_boot = false; | |||
uint32_t timeout = HAL_BOOTLOADER_TIMEOUT; | |||
|
|||
#if defined(HAL_BL_IOMCU_FW_DETECT) && HAL_BL_IOMCU_FW_DETECT | |||
if (is_iomcu_fw_present()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this needed? This seems to be forcing a shorter timeout if there is already a IO fw present, which seems odd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current iofirmware bootloader has 200ms timeout. Also if iofirmware doesn't boot faster than when AP_IOMCU tries to detect it, it will simply try to reflash.
void AP_memory_guard_error(uint16_t error); | ||
void AP_memory_guard_error(uint16_t error) { | ||
// simply panic for now | ||
AP_HAL::panic("PANIC: memory guard error %u", error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't a reboot be better? a panic will loop forever, causing the vehicle to crash with no IO
self.env_vars['IOMCU_FW'] = 0 | ||
|
||
# check if heater pin defined | ||
if 'HEATER' in self.bylabel.keys(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we already handle not having a heater with the HEATER_SET() macro, why also handle it at the build level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed to disable multiple builds for highpol and lowpol heaters. With hwdef without Heaters we were still doing that.
'#define HAL_UART_IO_DRIVER ChibiOS::UARTDriver uart_io(HAL_UART_IOMCU_IDX)\n' | ||
) | ||
serial_list.append(self.config['IOMCU_UART'][0]) | ||
if self.config['IOMCU_UART'][0].startswith('HAL_SERIAL'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we made AP_IOMCU take a pointer to a AP_HAL::UARTDriver instead of a reference then we could have an AP::iomcu()->set_uart() call that could be made from AP_SerialManager. That would enable runtime configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am going to do this in a separate PR, as that will require quite a decent amount of change to AP_IOMCU. A separate PR for this change will be much easier to review.
For this PR I can go part of the way and use SerialProtocol and hal.serial instead of current method of declairing a separate serial driver for all iomcu users.
libraries/AP_Vehicle/AP_Vehicle.cpp
Outdated
if (BoardConfig.io_enabled()) { | ||
// If IO is enabled, we need to set the protocol to None | ||
// as the IO MCU UART is handled by the AP_IOMCU class | ||
serial_manager.set_protocol_and_baud(HAL_UART_IOMCU_IDX, AP_SerialManager::SerialProtocol_None, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SerialProtocol_IOMCU would make more sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to SerialProtocol_IOMCU
libraries/AP_Vehicle/AP_Vehicle.cpp
Outdated
// as the IO MCU UART is handled by the AP_IOMCU class | ||
serial_manager.set_protocol_and_baud(HAL_UART_IOMCU_IDX, AP_SerialManager::SerialProtocol_None, 0); | ||
} else { | ||
iomcu.wipe(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we wiping the fw if IO not enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to allow flashing a different firmware to secondary. We have to reduce the boot time if IOMCU is enabled to 200ms, which is not long enough for it to be caught over USB. To allow updating Secondary MCU over USB again we need wipe iofirmware.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not relevant anymore, moved to different procedure to allow updates other than iofirmware.
d8a852b
to
8d6f33c
Compare
@tridge I have pushed changes per your comments.
|
8d6f33c
to
23e09cd
Compare
fixes watchdog trigger on call to trigger after enabling iomcu from disabled state
23e09cd
to
d67d2ce
Compare
|
||
define HAL_USE_RTC FALSE | ||
define HAL_NO_UARTDRIVER TRUE | ||
define HAL_LOGGING_ENABLED 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these in here? These are the default for io firmware... (defaults_periph.h)
define HAL_GPIO_PIN_SPEKTRUM_OUT PAL_LINE(GPIOC,11U) | ||
|
||
|
||
define AP_NETWORKING_BACKEND_PPP 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is odd?
#define STR(x) XSTR(x) | ||
#define XSTR(x) #x | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused?
@@ -95,6 +95,14 @@ THD_WORKING_AREA(_monitor_thread_wa, MONITOR_THD_WA_SIZE); | |||
#define AP_HAL_CHIBIOS_IN_EXPECTED_DELAY_WHEN_NOT_INITIALISED 1 | |||
#endif | |||
|
|||
#if defined(STM32H7) && defined(IOMCU_FW) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if defined(STM32H7) && defined(IOMCU_FW) | |
#if AP_REBOOT_ON_MEMGUARD_ERROR |
... and default it off and define to true in the hwdef.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd like to see binary cmp showing no change in IO fw builds
@@ -97,6 +101,14 @@ bool AP_IOMCU::upload_fw(void) | |||
} | |||
debug("found bootloader revision: %u", unsigned(bl_rev)); | |||
|
|||
if (bl_rev > 2) { | |||
// verify the CRC of the IO firmware | |||
if (verify_rev3(fw_size)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why add this in? It makes me a bit nervous to be changing this behaviour for existing boards
maybe ifdef it for only this "modern" IOMCU
debug("Err: failed to contact bootloader"); | ||
uint32_t bl_rev, unused; | ||
if (!get_info(INFO_BL_REV, bl_rev) || | ||
!get_info(INFO_BOARD_ID, unused) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think make these changes under #ifdef for IOMCU_CHIBIOS_BOOTLOADER
@@ -281,7 +293,7 @@ bool AP_IOMCU::erase() | |||
debug("erase..."); | |||
send(PROTO_CHIP_ERASE); | |||
send(PROTO_EOC); | |||
return get_sync(10000); | |||
return get_sync(20000); // 20s timeout for erase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ifdef IOMCU_CHIBIOS_BOOTLOADER or define for timeout
@@ -417,12 +429,13 @@ bool AP_IOMCU::verify_rev3(uint32_t fw_size_local) | |||
/* compare the CRC sum from the IO with the one calculated */ | |||
if (sum != crc) { | |||
debug("CRC wrong: received: 0x%x, expected: 0x%x", (unsigned)crc, (unsigned)sum); | |||
get_sync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ifdef
return false; | ||
} | ||
|
||
crc_is_ok = true; | ||
|
||
return true; | ||
return get_sync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ifdef
Tested working DSHOT, PWM modes and RC Input on CubredSecondary with IOFirmware.
No size changes for older iomcus, checked using sizecompare for both with and without dshot.
Allows updates to the secondary MCU's firmware even after the IOFirmware is flashed.