Skip to content

Commit

Permalink
Added DFU bootloader for lpc1756
Browse files Browse the repository at this point in the history
  • Loading branch information
itzandroidtab committed Sep 24, 2023
0 parents commit 534f1a2
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 0 deletions.
89 changes: 89 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: klib bootloader

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release

jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest

strategy:
matrix:
cpu: [ lpc1756 ]

steps:
- uses: actions/checkout@v3

- name: arm-none-eabi-gcc install
uses: carlosperate/arm-none-eabi-gcc-action@v1.6.0
with:
release: '12.2.Rel1'

- name: arm-none-eabi-gcc version
run: arm-none-eabi-gcc --version

- name: getting arm headers
uses: actions/checkout@v3
with:
repository: ARM-software/CMSIS_5
ref: 'develop'
fetch-depth: '1'
path: './CMSIS'

- name: moving arm headers
run: |
cp ${{github.workspace}}/CMSIS/CMSIS/Core/Include/* ${{github.workspace}}/targets/arm/
- name: generating header
run: |
mkdir -p ${{github.workspace}}/targets/${{matrix.cpu}}/docs
wget -q -O ${{github.workspace}}/targets/${{matrix.cpu}}/docs/${{matrix.cpu}}.svd https://raw.githubusercontent.com/itzandroidtab/klib-svd/master/${{matrix.cpu}}.svd
wget -q -O ${{github.workspace}}/svdconv.tbz2 https://github.com/Open-CMSIS-Pack/devtools/releases/download/tools%2Fsvdconv%2F3.3.44/svdconv-3.3.44-linux64-amd64.tbz2
tar -xf ${{github.workspace}}/svdconv.tbz2
chmod +x ${{github.workspace}}/svdconv
${{github.workspace}}/svdconv ${{github.workspace}}/targets/${{matrix.cpu}}/docs/${{matrix.cpu}}.svd --generate=header -o ${{github.workspace}}/targets/${{matrix.cpu}}/ > /dev/null || true
sed -i '/#include "system_/d' ${{github.workspace}}/targets/${{matrix.cpu}}/${{matrix.cpu}}.h
- name: Create main
# create a main file that includes all the header files for the current target
run: |
find ${{github.workspace}}/klib/ -type f -name "*.hpp" -exec echo "#include \"{}\"" >> ${{github.workspace}}/project/main.cpp \;
find ${{github.workspace}}/targets/${{matrix.cpu}} -type f -name "*.hpp" -exec echo "#include \"{}\"" >> ${{github.workspace}}/project/main.cpp \;
echo "int main() {return 0;}" >> ${{github.workspace}}/project/main.cpp
echo "Contents of main:"
cat ${{github.workspace}}/project/main.cpp
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: CC=arm-none-eabi-gcc CXX=arm-none-eabi-g++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DTARGET_CPU=${{matrix.cpu}}

- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

- name: Uploading artifact
uses: actions/upload-artifact@v3
# upload the elf file as a artifact
with:
name: ${{matrix.cpu}}
path: |
${{github.workspace}}/build/project/klib.elf
${{github.workspace}}/build/project/klib.map
${{github.workspace}}/build/project/klib.lss
${{github.workspace}}/build/project/klib.memory
${{github.workspace}}/build/project/klib.hex
${{github.workspace}}/build/project/klib.bin
48 changes: 48 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# set the sources
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)

set(HEADERS)

# add our executable
add_executable(klib_project
${SOURCES} ${HEADERS}
)

# set the output filename
set_target_properties(klib_project PROPERTIES OUTPUT_NAME "klib" SUFFIX ".elf")

# set the interrupt implementation
target_compile_definitions(klib PUBLIC "KLIB_IRQ=irq_ram")
# target_compile_definitions(klib PUBLIC "KLIB_IRQ=irq_hooked")
# target_compile_definitions(klib PUBLIC "KLIB_IRQ=irq_flash")

# set the default cout/cin
# target_compile_definitions(klib PUBLIC "KLIB_DEFAULT_COUT=rtt")
# target_compile_definitions(klib PUBLIC "KLIB_DEFAULT_CIN=rtt")

# override the rtt buffer size (not required and not used when no segger rtt is used)
target_compile_definitions(klib PUBLIC "BUFFER_SIZE_UP=256")
target_compile_definitions(klib PUBLIC "BUFFER_SIZE_DOWN=16")

# link the klib_project to klib and the cpu target
target_link_libraries(klib_project PUBLIC klib)
target_link_libraries(klib_project PUBLIC target_cpu)

# Libraries to link for all targets
target_link_libraries(klib_project PUBLIC m)

# link to the linkerscript of the target cpu
target_link_options(klib_project PUBLIC "-T${TARGET_LINKERSCRIPT}")
set_target_properties(klib_project PROPERTIES LINK_DEPENDS ${TARGET_LINKERSCRIPT})

# add the project directory to the include directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR})

# Custom commands for processing the build binary and show some statistics and debug info
add_custom_command(TARGET klib_project DEPENDS ${CMAKE_BINARY_DIR}/klib.elf POST_BUILD COMMAND arm-none-eabi-objcopy ARGS -O binary -R .bss -R .stack klib.elf klib.bin)
add_custom_command(TARGET klib_project DEPENDS ${CMAKE_BINARY_DIR}/klib.elf POST_BUILD COMMAND arm-none-eabi-objcopy ARGS -O ihex -R .bss -R .stack klib.elf klib.hex)
add_custom_command(TARGET klib_project DEPENDS ${CMAKE_BINARY_DIR}/klib.elf POST_BUILD COMMAND arm-none-eabi-objdump ARGS -C -S klib.elf > klib.lss)
add_custom_command(TARGET klib_project DEPENDS ${CMAKE_BINARY_DIR}/klib.elf POST_BUILD COMMAND arm-none-eabi-objdump ARGS -C -sj .bss -sj .data -sj .rodata -sj .vectors -S klib.elf > klib.memory)
add_custom_command(TARGET klib_project DEPENDS ${CMAKE_BINARY_DIR}/klib.elf POST_BUILD COMMAND arm-none-eabi-size ARGS -A klib.elf -x)
147 changes: 147 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#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>

namespace target = klib::target;

// location of the user vector table
constexpr static uint32_t app_vector_address = 0x2000;

// transfer buffer size. Same value is used as the write amount
constexpr static uint32_t transfer_size = 256;

/**
* @brief Helper class to write to flash memory
*
*/
class dfu {
public:
/**
* @brief Write memory to flash
*
* @param offset
* @param data
* @param length
* @return true
* @return false
*/
static bool write(uint32_t offset, uint8_t* data, uint32_t length) {
// get the address we are trying to write
const uint32_t address = app_vector_address + offset;

// check if we are at the start of the sector
const bool start_sector = (
target::io::flash::address_to_sector(address) ==
target::io::flash::address_to_sector(address + (0x1000 - 1))
);

// 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)
return target::io::flash::write(address, data, transfer_size);
}

/**
* @brief Get the write timeout
*
* @return uint32_t
*/
static uint32_t get_write_timeout() {
return 1;
}

/**
* @brief Callback that gets called when the CPU should
* be reset
*
*/
static void reset() {
// do a system reset
NVIC_SystemReset();
}
};

// using for the usb driver
using usb_bulk = 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<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
asm volatile ("MSR msp, %0" : : "r" (*reinterpret_cast<uint32_t*>(app_vector_address)) : );

// call the user application
(*reinterpret_cast<void(**)()>((app_vector_address + 0x4)))();

while (true) {}
}

int main() {
// get the bootloader pin
using bootloader_pin = target::io::pin_in<target::pins::package::lqfp_80::p40>;

// 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 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_bulk::init<true, true, false>();

// wait until we are reset in the dfu handler
while (true) {
// do nothing
}
}

0 comments on commit 534f1a2

Please sign in to comment.