-
Notifications
You must be signed in to change notification settings - Fork 18k
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)
@@ -58,6 +58,14 @@ | |||
extern AP_IOMCU iomcu; | |||
#endif | |||
|
|||
#ifdef 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.
This is only with H7 I think? Probably should add that to the 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.
done
libraries/AP_IOMCU/AP_IOMCU.cpp
Outdated
@@ -100,6 +104,34 @@ void AP_IOMCU::init(void) | |||
initialised = true; | |||
} | |||
|
|||
/* | |||
disable the IOMCU operation by erasing 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.
I think this should have a different name given the fairly radical function of its operation
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.
thoughts on name, erase is already taken.
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.
changing it to wipe
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.
@@ -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?
@@ -22,6 +22,8 @@ | |||
#include "hal.h" | |||
#include "analog.h" | |||
|
|||
#ifdef HAL_DISABLE_ADC_DRIVER |
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 supposed to be ifndef?
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.
no, that is correct. If AP::HAL ADC Driver is disabled analog.cpp handles ADC periph
Otherwise we use hal.analogin
@@ -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.
*/ | ||
#if defined(HAL_BL_IOMCU_FW_DETECT) && HAL_BL_IOMCU_FW_DETECT | ||
#define HAL_IOMCU_MAGIC 0x937E638A | ||
uint32_t is_iomcu_fw_present(void) |
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 understand why this is needed
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 so we can reduce the boot time if IOMCU is present to 200ms,. This is done by reading the IOMCU_FW_DETECT magic written to the end of flash.
I think I am going to add a boot time field to AP_CheckFirmware instead. Was looking for a shortcut but this hasn't turned out to be a clean implementation.
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?
@@ -1052,6 +1052,17 @@ def write_mcu_config(self, f): | |||
else: | |||
self.env_vars['IOMCU_FW'] = 0 | |||
|
|||
if self.get_config('IOMCU_FW', required=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.
cut and paste duplication?
'#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.
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
// 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.
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.