- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
Latest commit
153 lines (126 loc) · 4.62 KB
/
Copy pathmain.cpp
File metadata and controls
153 lines (126 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include<klib/klib.hpp>
#include<klib/usb/device/dfu.hpp>
#include<io/usb.hpp>
#include<io/system.hpp>
#include<io/pins.hpp>
#include<io/flash.hpp>
namespacetarget= klib::target;
// location of the user vector table
constexprstaticuint32_t app_vector_address = 0x2000;
// transfer buffer size. Same value is used as the write amount
constexprstaticuint32_t transfer_size = 256;
/**
* @brief Helper class to write to flash memory
*
*/
classdfu {
public:
/**
* @brief Write memory to flash
*
* @param offset
* @param data
* @param length
* @return true
* @return false
*/
staticboolwrite(constuint32_t offset, constuint8_t* data, constuint32_t length) {
// get the address we are trying to write
constuint32_t address = app_vector_address + offset;
// get the target sector
constuint32_t sector = target::io::flash::address_to_sector(address);
// check if we are at the start of the sector
constbool start_sector = (
target::io::flash::sector_to_address(sector) == address
);
// check if we should erase the currect sector by
// checking if it is blank (only do it when we are
// at the start of the sector)
if (start_sector && !target::io::flash::is_blank(address)) {
// flash is not blank. Erase it
target::io::flash::erase(target::io::flash::erase_mode::sector, address);
}
// write the data to the flash (always write the full dfu buffer size)
returntarget::io::flash::write(address, std::span<constuint8_t>{data, transfer_size});
}
/**
* @brief Get the write timeout
*
* @return uint32_t
*/
staticuint32_tget_write_timeout() {
return1;
}
/**
* @brief Callback that gets called when the CPU should
* be reset
*
*/
staticvoidreset() {
// do a system reset
NVIC_SystemReset();
}
};
// using for the usb driver
using usb_dfu = target::io::usb<target::io::periph::lqfp_80::usb0, klib::usb::device::dfu<dfu, transfer_size>>;
/**
* @brief Helper function that moves the vector table and
* starts the user application
*
* @warning this function resets the stack pointer to the
* address in the vector table of the user code. This
* function should not use the stack after this is done
*
*/
static__attribute__((__noreturn__, __naked__)) void start_application() {
// helper using for moving the vector table
using irq = klib::irq_flash<0, 16>;
// move the vector table to the vector table
// of the user
irq::init(reinterpret_cast<irq::interrupt_callback*>(app_vector_address));
// load the stack pointer of the application
asmvolatile ("MSR msp, %0" : : "r" (*reinterpret_cast<uint32_t*>(app_vector_address)) : );
// call the user application
(*reinterpret_cast<void(**)()>((app_vector_address + 0x4)))();
}
intmain() {
// get the bootloader pin
using bootloader_pin = target::io::pin_in<target::pins::package::lqfp_80::p39>;
// init it as a pin in
bootloader_pin::init();
// check if we should run the user application
if (!bootloader_pin::get() && !target::io::flash::is_blank(app_vector_address)) {
// boot the application
start_application();
// we will never get here as "start_application"
// has the noreturn attribute. We are also
// overriding the stack. This prevents the user
// application from returning to this place as
// the stack is probably pointing somewhere
// else by then
}
// Setup the target specific hardware. When
// changing hardware this would have to be
// changed (this is done here as startup.cpp
// is not compiled in the bootloader)
{
// setup the flash wait state to 4 + 1 CPU clocks
target::io::system::flash::setup<4>();
// using for setting up the main clock
using clock = target::io::system::clock;
// setup the clock to 96Mhz from the 12mhz oscillator
// to speed up the dfu flash programming
// (((15 + 1) * 2 * 12Mhz) / (0 + 1) = 384Mhz) / (3 + 1) = 96Mhz
clock::set_main<clock::source::main, 96'000'000, 15, 0, 3>();
// setup the vector table for the usb interrupts
target::irq::init();
// bootloader mode. configure the usb pll
target::io::system::clock::set_usb<12'000'000>();
}
// init the usb hardware
usb_dfu::init<true, true, false>();
// wait until we are reset in the dfu handler
while (true) {
// do nothing
}
}