software_dfu #46
|
@ -124,7 +124,7 @@ formatted as line-delimited JSON.
|
|||
| `load [0/1]` | Restore configuration for channel all/0/1 from flash |
|
||||
| `save [0/1]` | Save configuration for channel all/0/1 to flash |
|
||||
| `reset` | Reset the device |
|
||||
| `dfu` | Reset device and enters USB device firmware update (DFU) mode |
|
||||
| `dfu` | Reset device and enters USB device firmware update (DFU) mode |
|
||||
|
||||
| `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway |
|
||||
|
||||
|
||||
|
|
5
memory.x
|
@ -3,12 +3,13 @@ MEMORY
|
|||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
|
||||
/* reserved for config data */
|
||||
CONFIG (rx) : ORIGIN = 0x8100000, LENGTH = 16K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 111K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K - 4
|
||||
/* reserved for DFU trigger message */
|
||||
DFU_MSG (wrx) : ORIGIN = 0x2001BC00, LENGTH = 1K
|
||||
DFU_MSG (wrx) : ORIGIN = 0x2001BFFC, LENGTH = 4
|
||||
sb10q
commented
The length should be 4 and not 1K AFAICT? The length should be 4 and not 1K AFAICT?
|
||||
RAM2 (xrw) : ORIGIN = 0x2001C000, LENGTH = 16K
|
||||
RAM3 (xrw) : ORIGIN = 0x20020000, LENGTH = 64K
|
||||
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
|
||||
}
|
||||
|
||||
_stack_start = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
|
||||
_dfu_msg = ORIGIN(DFU_MSG);
|
||||
|
|
49
src/dfu.rs
|
@ -1,28 +1,25 @@
|
|||
use cortex_m_rt::{pre_init};
|
||||
|
||||
/// RAM location used to store DFU trigger message
|
||||
const DFU_MSG_ADDR: usize = 0x2001BC00;
|
||||
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
|
||||
|
||||
sb10q
commented
This can and should be automatically obtained via a linker symbol. See this example: This can and should be automatically obtained via a linker symbol. See this example:
https://git.m-labs.hk/M-Labs/artiq-zynq/src/branch/master/src/runtime/src/kernel/core1.rs#L31-L36
https://git.m-labs.hk/M-Labs/artiq-zynq/src/branch/master/src/runtime/link.x#L10
topquark12
commented
The linker currently does not actually do anything to the ram carved out for the dfu trigger message, and I beleive there's no symbol generated for that chunk of memory. I think I'll have to find the linker script the project is using, fork a copy, generate a symbol for that addr and use it in our project somehow. The linker currently does not actually do anything to the ram carved out for the dfu trigger message, and I beleive there's no symbol generated for that chunk of memory.
I think I'll have to find the linker script the project is using, fork a copy, generate a symbol for that addr and use it in our project somehow.
sb10q
commented
Indeed, but the linker script can be modified so that such a symbol is generated. This way there isn't any value that needs to be manually synchronized in two places. You may not even need to hardcode the address; the linker could place that variable automatically. Indeed, but the linker script can be modified so that such a symbol is generated. This way there isn't any value that needs to be manually synchronized in two places. You may not even need to hardcode the address; the linker could place that variable automatically.
sb10q
commented
Though hardcoding is actually more reliable since after a firmware update the address could have changed otherwise... add a comment that explains that. Though hardcoding is actually more reliable since after a firmware update the address could have changed otherwise... add a comment that explains that.
sb10q
commented
The linker script is the second link I gave you. The linker script is the second link I gave you.
pca006132
commented
I think specifying a region that only contains the DFU msg would be reasonable. This way the address would not be changed after update. I think specifying a region that only contains the DFU msg would be reasonable. This way the address would not be changed after update.
topquark12
commented
I thought that linker script is for a zynq? I am not sure where the linker script currently being used is placed, think it is packaged with one of the rust modules. I thought that linker script is for a zynq? I am not sure where the linker script currently being used is placed, think it is packaged with one of the rust modules.
sb10q
commented
Okay, you mean the thermostat linker script. Okay, you mean the thermostat linker script.
That ``memory.x`` you modified can be used, as you can see it already defines the ``_stack_start`` symbol.
topquark12
commented
The stack is on CCM, the message is placed in RAM. I can try placing the msg in CCM, not sure what the reset behavior of CCM is yet. The stack is on CCM, the message is placed in RAM. I can try placing the msg in CCM, not sure what the reset behavior of CCM is yet.
topquark12
commented
@pca006132 There's already a dedicated region specified in memory.x . Though the linker does not do anything with that region, and I don't think the linker generates a symbol for that space. I also haven't found the linker script of the project just yet. @pca006132 There's already a dedicated region specified in memory.x . Though the linker does not do anything with that region, and I don't think the linker generates a symbol for that space.
I also haven't found the linker script of the project just yet.
pca006132
commented
The linker script is defined in The linker script is defined in `cortex-m-rt`, https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in
But I'm not familiar with that, not sure how to add new symbols.
sb10q
commented
@topquark12 what's wrong with simply adding
at the end of thermostat's @topquark12 what's wrong with simply adding
```
_dfu_msg = ORIGIN(DFU_MSG)
```
at the end of thermostat's ``memory.x``?
|
||||
/// DFU trigger message
|
||||
const DFU_TRIG_MSG: usize = 0xDECAFBAD;
|
||||
|
||||
/// Set DFU trigger
|
||||
pub unsafe fn trig_dfu() {
|
||||
let dfu_msg_addr = DFU_MSG_ADDR as *mut usize;
|
||||
*dfu_msg_addr = DFU_TRIG_MSG;
|
||||
pub unsafe fn set_dfu_trigger() {
|
||||
extern "C" {
|
||||
sb10q
commented
Why not put it outside the functions so this declaration can be shared? Why not put it outside the functions so this declaration can be shared?
|
||||
static mut _dfu_msg: u32;
|
||||
}
|
||||
_dfu_msg = DFU_TRIG_MSG;
|
||||
}
|
||||
|
||||
/// Called by reset handler in lib.rs immediately after reset, checks if booting into dfu is needed
|
||||
/// Called by reset handler in lib.rs immediately after reset.
|
||||
/// This function should not be called outside of reset handler as
|
||||
/// bootloader expects MCU to be in reset state when called.
|
||||
#[pre_init]
|
||||
unsafe fn __pre_init() {
|
||||
extern "C" {
|
||||
sb10q
commented
see comment above see comment above
|
||||
static mut _dfu_msg: u32;
|
||||
sb10q
commented
remove blank line remove blank line
|
||||
}
|
||||
|
||||
let dfu_msg_addr = DFU_MSG_ADDR as *mut usize;
|
||||
|
||||
// Check DFU trigger message
|
||||
if *dfu_msg_addr == DFU_TRIG_MSG{
|
||||
|
||||
// Reset message
|
||||
*dfu_msg_addr = 0x00000000;
|
||||
if _dfu_msg == DFU_TRIG_MSG {
|
||||
_dfu_msg = 0x00000000;
|
||||
sb10q
commented
space before { space before {
|
||||
|
||||
sb10q
commented
remove blank line remove blank line
|
||||
// Enable system config controller clock
|
||||
const RCC_APB2ENR: *mut u32 = 0xE000_ED88 as *mut u32;
|
||||
|
@ -41,14 +38,14 @@ unsafe fn __pre_init() {
|
|||
SYSCFG_MEMRMP,
|
||||
*SYSCFG_MEMRMP | SYSCFG_MEMRMP_MAP_ROM,
|
||||
);
|
||||
|
||||
// Set stack pointer to bootloader location
|
||||
asm!("LDR R0, =0x1FFF0000");
|
||||
asm!("LDR SP,[R0, #0]");
|
||||
|
||||
// Jump to bootloader
|
||||
asm!("LDR R0,[R0, #4]");
|
||||
asm!("BX R0");
|
||||
|
||||
asm!(
|
||||
// Set stack pointer to bootloader location
|
||||
"LDR R0, =0x1FFF0000",
|
||||
"LDR SP,[R0, #0]",
|
||||
// Jump to bootloader
|
||||
"LDR R0,[R0, #4]",
|
||||
"BX R0",
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
sb10q
commented
You can put all these lines into a single You can put all these lines into a single ``asm!`` macro, see https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html
|
|
@ -429,8 +429,9 @@ fn main() -> ! {
|
|||
channels.power_down(i);
|
||||
}
|
||||
unsafe {
|
||||
dfu::trig_dfu();
|
||||
dfu::set_dfu_trigger();
|
||||
}
|
||||
socket.close();
|
||||
sb10q
commented
Does this work or do we need to wait for the network driver/hardware to actually send the packet? Does this work or do we need to wait for the network driver/hardware to actually send the packet?
What if there are other open sockets? Maybe address this entire issue in a second PR.
topquark12
commented
was just testing out the behavior of that, forgot to remove before committing. was just testing out the behavior of that, forgot to remove before committing.
|
||||
SCB::sys_reset();
|
||||
}
|
||||
}
|
||||
|
|
Table formatting does not seem OK.