Initial check-in for STM32 board

This commit is contained in:
Ben Lye
2017-11-27 21:19:49 +00:00
parent 9bf5b0c9a7
commit e557155b17
893 changed files with 106516 additions and 34 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
#!/usr/bin/awk -f
# libmaple's own Evil Mangler
#
# Input filter hack to trick Doxygen into thinking that a series
# header is in a separate namespace. This is necessary because Doxygen
# doesn't know how to cope with two data structures with the same name
# in different places in the project. (We do that all the time,
# e.g. for foo_reg_map structs.)
#
# E.g., an STM32F1 header gets transformed into:
#
# namespace stm32f1 {
# <contents of header>
# }
BEGIN {
# For extracting series component from header FILENAME.
series_regex = "/stm32[flw][0-9]*/";
# Holds header FILENAME. Cargo-culted; not sure why it's necessary.
f = "";
# Holds series component.
series = "";
}
{
if (f != FILENAME) {
f = FILENAME;
match(f, series_regex);
series = substr(f, RSTART + 1, RLENGTH - 2);
printf("namespace %s {\n", series);
}
print;
}
END {
if (series != "") {
print "}"
}
}

View File

@@ -0,0 +1,12 @@
set print pretty on
print "GPIOA registers:"
p/x *GPIOA->regs
print "GPIOB registers:"
p/x *GPIOB->regs
print "GPIOC registers:"
p/x *GPIOC->regs
print "GPIOD registers:"
p/x *GPIOD->regs
print "AFIO registers:"
p/x *(struct afio_reg_map*)0x40010000

View File

@@ -0,0 +1,112 @@
define i2c_sr1_flags
set $s = $arg0
printf "SR1: "
if (($s & (1 << 15)))
printf "SMBALERT "
end
if (($s & (1 << 14)))
printf "TIMEOUT "
end
if (($s & (1 << 12)))
printf "PECERR "
end
if (($s & (1 << 11)))
printf "OVR "
end
if (($s & (1 << 10)))
printf "AF "
end
if (($s & (1 << 9)))
printf "ARLO "
end
if (($s & (1 << 8)))
printf "BERR "
end
if (($s & (1 << 7)))
printf "TXE "
end
if (($s & (1 << 6)))
printf "RXNE "
end
if (($s & (1 << 4)))
printf "STOPF "
end
if (($s & (1 << 3)))
printf "ADD10 "
end
if (($s & (1 << 2)))
printf "BTF "
end
if (($s & (1 << 1)))
printf "ADDR "
end
if (($s & (1 << 0)))
printf "SB "
end
end
define i2c_sr2_flags
set $s = $arg0
printf "SR2: "
if (($s & (1 << 7)))
printf "DUALF "
end
if (($s & (1 << 6)))
printf "SMBHOST "
end
if (($s & (1 << 5)))
printf "SMBDEFAULT "
end
if (($s & (1 << 4)))
printf "GENCALL "
end
if (($s & (1 << 2)))
printf "TRA "
end
if (($s & (1 << 1)))
printf "BUSY "
end
if (($s & (1 << 0)))
printf "MSL "
end
end
define pbc
set $c = crumbs
while ($c->event)
if ($c->event != 0)
printf "Event: %d ", $c->event
if ($c->event == 1)
i2c_sr1_flags $c->sr1
printf "\t"
i2c_sr2_flags $c->sr2
end
printf "\n"
end
set $c = $c + 1
end

View File

@@ -0,0 +1,219 @@
/*
* Linker script for libmaple.
*
* Original author "lanchon" from ST forums, with modifications by LeafLabs.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Configure other libraries we want in the link.
*
* libgcc, libc, and libm are common across supported toolchains.
* However, some toolchains require additional archives which aren't
* present everywhere (e.g. ARM's gcc-arm-embedded releases).
*
* To hack around this, we let the build system specify additional
* archives by putting the right extra_libs.inc (in a directory under
* toolchains/) in our search path.
*/
GROUP(libgcc.a libc.a libm.a)
INCLUDE extra_libs.inc
/*
* These force the linker to search for vector table symbols.
*
* These symbols vary by STM32 family (and also within families).
* It's up to the build system to configure the link's search path
* properly for the target MCU.
*/
INCLUDE vector_symbols.inc
/* STM32 vector table. */
EXTERN(__stm32_vector_table)
/* C runtime initialization function. */
EXTERN(start_c)
/* main entry point */
EXTERN(main)
/* Initial stack pointer value. */
EXTERN(__msp_init)
PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
/* Reset vector and chip reset entry point */
EXTERN(__start__)
ENTRY(__start__)
PROVIDE(__exc_reset = __start__);
/* Heap boundaries, for libmaple */
EXTERN(_lm_heap_start);
EXTERN(_lm_heap_end);
SECTIONS
{
.text :
{
__text_start__ = .;
/*
* STM32 vector table. Leave this here. Yes, really.
*/
*(.stm32.interrupt_vector)
/*
* Program code and vague linking
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
} > REGION_TEXT
/*
* End of text
*/
.text.align :
{
. = ALIGN(8);
__text_end__ = .;
} > REGION_TEXT
/*
* .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
*/
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > REGION_RODATA
__exidx_end = .;
/*
* .data
*/
.data :
{
. = ALIGN(8);
__data_start__ = .;
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(8);
__data_end__ = .;
} > REGION_DATA AT> REGION_RODATA
/*
* Read-only data
*/
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .USER_FLASH: We allow users to allocate into Flash here */
*(.USER_FLASH)
/* ROM image configuration; for C startup */
. = ALIGN(4);
_lm_rom_img_cfgp = .;
LONG(LOADADDR(.data));
/*
* Heap: Linker scripts may choose a custom heap by overriding
* _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
* internal SRAM, beginning after .bss, and growing towards
* the stack.
*
* I'm shoving these here naively; there's probably a cleaner way
* to go about this. [mbolivar]
*/
_lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end;
_lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
} > REGION_RODATA
/*
* .bss
*/
.bss :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
__bss_end__ = .;
_end = __bss_end__;
} > REGION_BSS
/*
* Debugging sections
*/
.stab 0 (NOLOAD) : { *(.stab) }
.stabstr 0 (NOLOAD) : { *(.stabstr) }
/* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}

View File

@@ -0,0 +1,26 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-flash.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@@ -0,0 +1,31 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-jtag.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@@ -0,0 +1,25 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-ram.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@@ -0,0 +1,3 @@
/* Specify heap boundary addresses on the external SRAM chip */
_lm_heap_start = 0x60000000;
_lm_heap_end = 0x60100000;

View File

@@ -0,0 +1,7 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
}
INCLUDE maple_native_heap.inc

View File

@@ -0,0 +1,7 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
INCLUDE maple_native_heap.inc

View File

@@ -0,0 +1,7 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}
INCLUDE maple_native_heap.inc

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 0K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08003000, LENGTH = 108K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 0K
}

View File

@@ -0,0 +1,78 @@
EXTERN(__msp_init)
EXTERN(__exc_reset)
EXTERN(__exc_nmi)
EXTERN(__exc_hardfault)
EXTERN(__exc_memmanage)
EXTERN(__exc_busfault)
EXTERN(__exc_usagefault)
EXTERN(__stm32reservedexception7)
EXTERN(__stm32reservedexception8)
EXTERN(__stm32reservedexception9)
EXTERN(__stm32reservedexception10)
EXTERN(__exc_svc)
EXTERN(__exc_debug_monitor)
EXTERN(__stm32reservedexception13)
EXTERN(__exc_pendsv)
EXTERN(__exc_systick)
EXTERN(__irq_wwdg)
EXTERN(__irq_pvd)
EXTERN(__irq_tamper)
EXTERN(__irq_rtc)
EXTERN(__irq_flash)
EXTERN(__irq_rcc)
EXTERN(__irq_exti0)
EXTERN(__irq_exti1)
EXTERN(__irq_exti2)
EXTERN(__irq_exti3)
EXTERN(__irq_exti4)
EXTERN(__irq_dma1_channel1)
EXTERN(__irq_dma1_channel2)
EXTERN(__irq_dma1_channel3)
EXTERN(__irq_dma1_channel4)
EXTERN(__irq_dma1_channel5)
EXTERN(__irq_dma1_channel6)
EXTERN(__irq_dma1_channel7)
EXTERN(__irq_adc)
EXTERN(__irq_usb_hp_can_tx)
EXTERN(__irq_usb_lp_can_rx0)
EXTERN(__irq_can_rx1)
EXTERN(__irq_can_sce)
EXTERN(__irq_exti9_5)
EXTERN(__irq_tim1_brk)
EXTERN(__irq_tim1_up)
EXTERN(__irq_tim1_trg_com)
EXTERN(__irq_tim1_cc)
EXTERN(__irq_tim2)
EXTERN(__irq_tim3)
EXTERN(__irq_tim4)
EXTERN(__irq_i2c1_ev)
EXTERN(__irq_i2c1_er)
EXTERN(__irq_i2c2_ev)
EXTERN(__irq_i2c2_er)
EXTERN(__irq_spi1)
EXTERN(__irq_spi2)
EXTERN(__irq_usart1)
EXTERN(__irq_usart2)
EXTERN(__irq_usart3)
EXTERN(__irq_exti15_10)
EXTERN(__irq_rtcalarm)
EXTERN(__irq_usbwakeup)
EXTERN(__irq_tim8_brk)
EXTERN(__irq_tim8_up)
EXTERN(__irq_tim8_trg_com)
EXTERN(__irq_tim8_cc)
EXTERN(__irq_adc3)
EXTERN(__irq_fsmc)
EXTERN(__irq_sdio)
EXTERN(__irq_tim5)
EXTERN(__irq_spi3)
EXTERN(__irq_uart4)
EXTERN(__irq_uart5)
EXTERN(__irq_tim6)
EXTERN(__irq_tim7)
EXTERN(__irq_dma2_channel1)
EXTERN(__irq_dma2_channel2)
EXTERN(__irq_dma2_channel3)
EXTERN(__irq_dma2_channel4_5)

View File

@@ -0,0 +1,78 @@
EXTERN(__msp_init)
EXTERN(__exc_reset)
EXTERN(__exc_nmi)
EXTERN(__exc_hardfault)
EXTERN(__exc_memmanage)
EXTERN(__exc_busfault)
EXTERN(__exc_usagefault)
EXTERN(__stm32reservedexception7)
EXTERN(__stm32reservedexception8)
EXTERN(__stm32reservedexception9)
EXTERN(__stm32reservedexception10)
EXTERN(__exc_svc)
EXTERN(__exc_debug_monitor)
EXTERN(__stm32reservedexception13)
EXTERN(__exc_pendsv)
EXTERN(__exc_systick)
EXTERN(__irq_wwdg)
EXTERN(__irq_pvd)
EXTERN(__irq_tamper)
EXTERN(__irq_rtc)
EXTERN(__irq_flash)
EXTERN(__irq_rcc)
EXTERN(__irq_exti0)
EXTERN(__irq_exti1)
EXTERN(__irq_exti2)
EXTERN(__irq_exti3)
EXTERN(__irq_exti4)
EXTERN(__irq_dma1_channel1)
EXTERN(__irq_dma1_channel2)
EXTERN(__irq_dma1_channel3)
EXTERN(__irq_dma1_channel4)
EXTERN(__irq_dma1_channel5)
EXTERN(__irq_dma1_channel6)
EXTERN(__irq_dma1_channel7)
EXTERN(__irq_adc1)
EXTERN(__stm32reservedexception14)
EXTERN(__stm32reservedexception15)
EXTERN(__stm32reservedexception16)
EXTERN(__stm32reservedexception17)
EXTERN(__irq_exti9_5)
EXTERN(__irq_tim1_brk)
EXTERN(__irq_tim1_up)
EXTERN(__irq_tim1_trg_com)
EXTERN(__irq_tim1_cc)
EXTERN(__irq_tim2)
EXTERN(__irq_tim3)
EXTERN(__irq_tim4)
EXTERN(__irq_i2c1_ev)
EXTERN(__irq_i2c1_er)
EXTERN(__irq_i2c2_ev)
EXTERN(__irq_i2c2_er)
EXTERN(__irq_spi1)
EXTERN(__irq_spi2)
EXTERN(__irq_usart1)
EXTERN(__irq_usart2)
EXTERN(__irq_usart3)
EXTERN(__irq_exti15_10)
EXTERN(__irq_rtcalarm)
EXTERN(__irq_cec)
EXTERN(__irq_tim12)
EXTERN(__irq_tim13)
EXTERN(__irq_tim14)
EXTERN(__stm32reservedexception18)
EXTERN(__stm32reservedexception19)
EXTERN(__irq_fsmc)
EXTERN(__stm32reservedexception20)
EXTERN(__irq_tim5)
EXTERN(__irq_spi3)
EXTERN(__irq_uart4)
EXTERN(__irq_uart5)
EXTERN(__irq_tim6)
EXTERN(__irq_tim7)
EXTERN(__irq_dma2_channel1)
EXTERN(__irq_dma2_channel2)
EXTERN(__irq_dma2_channel3)
EXTERN(__irq_dma2_channel4_5)
EXTERN(__irq_dma2_channel5) /* on remap only */

View File

@@ -0,0 +1,98 @@
EXTERN(__msp_init)
EXTERN(__exc_reset)
EXTERN(__exc_nmi)
EXTERN(__exc_hardfault)
EXTERN(__exc_memmanage)
EXTERN(__exc_busfault)
EXTERN(__exc_usagefault)
EXTERN(__stm32reservedexception7)
EXTERN(__stm32reservedexception8)
EXTERN(__stm32reservedexception9)
EXTERN(__stm32reservedexception10)
EXTERN(__exc_svc)
EXTERN(__exc_debug_monitor)
EXTERN(__stm32reservedexception13)
EXTERN(__exc_pendsv)
EXTERN(__exc_systick)
EXTERN(__irq_wwdg)
EXTERN(__irq_pvd)
EXTERN(__irq_tamp_stamp)
EXTERN(__irq_rtc_wkup)
EXTERN(__irq_flash)
EXTERN(__irq_rcc)
EXTERN(__irq_exti0)
EXTERN(__irq_exti1)
EXTERN(__irq_exti2)
EXTERN(__irq_exti3)
EXTERN(__irq_exti4)
EXTERN(__irq_dma1_stream0)
EXTERN(__irq_dma1_stream1)
EXTERN(__irq_dma1_stream2)
EXTERN(__irq_dma1_stream3)
EXTERN(__irq_dma1_stream4)
EXTERN(__irq_dma1_stream5)
EXTERN(__irq_dma1_stream6)
EXTERN(__irq_adc)
EXTERN(__irq_can1_tx)
EXTERN(__irq_can1_rx0)
EXTERN(__irq_can1_rx1)
EXTERN(__irq_can1_sce)
EXTERN(__irq_exti9_5)
EXTERN(__irq_tim1_brk_tim9)
EXTERN(__irq_tim1_up_tim10)
EXTERN(__irq_tim1_trg_com_tim11)
EXTERN(__irq_tim1_cc)
EXTERN(__irq_tim2)
EXTERN(__irq_tim3)
EXTERN(__irq_tim4)
EXTERN(__irq_i2c1_ev)
EXTERN(__irq_i2c1_er)
EXTERN(__irq_i2c2_ev)
EXTERN(__irq_i2c2_er)
EXTERN(__irq_spi1)
EXTERN(__irq_spi2)
EXTERN(__irq_usart1)
EXTERN(__irq_usart2)
EXTERN(__irq_usart3)
EXTERN(__irq_exti15_10)
EXTERN(__irq_rtc_alarm)
EXTERN(__irq_otg_fs_wkup)
EXTERN(__irq_tim8_brk_tim12)
EXTERN(__irq_tim8_up_tim13)
EXTERN(__irq_tim8_trg_com_tim14)
EXTERN(__irq_tim8_cc)
EXTERN(__irq_dma1_stream7)
EXTERN(__irq_fsmc)
EXTERN(__irq_sdio)
EXTERN(__irq_tim5)
EXTERN(__irq_spi3)
EXTERN(__irq_uart4)
EXTERN(__irq_uart5)
EXTERN(__irq_tim6_dac)
EXTERN(__irq_tim7)
EXTERN(__irq_dma2_stream0)
EXTERN(__irq_dma2_stream1)
EXTERN(__irq_dma2_stream2)
EXTERN(__irq_dma2_stream3)
EXTERN(__irq_dma2_stream4)
EXTERN(__irq_eth)
EXTERN(__irq_eth_wkup)
EXTERN(__irq_can2_tx)
EXTERN(__irq_can2_rx0)
EXTERN(__irq_can2_rx1)
EXTERN(__irq_can2_sce)
EXTERN(__irq_otg_fs)
EXTERN(__irq_dma2_stream5)
EXTERN(__irq_dma2_stream6)
EXTERN(__irq_dma2_stream7)
EXTERN(__irq_usart6)
EXTERN(__irq_i2c3_ev)
EXTERN(__irq_i2c3_er)
EXTERN(__irq_otg_hs_ep1_out)
EXTERN(__irq_otg_hs_ep1_in)
EXTERN(__irq_otg_hs_wkup)
EXTERN(__irq_otg_hs)
EXTERN(__irq_dcmi)
EXTERN(__irq_cryp)
EXTERN(__irq_hash_rng)

View File

@@ -0,0 +1,7 @@
/*
* Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi-
* releases (https://launchpad.net/gcc-arm-embedded/).
*/
/* This is for the provided newlib. */
GROUP(libnosys.a)

View File

@@ -0,0 +1,7 @@
MCU := STM32F100RB
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOC
ERROR_LED_PIN := 9
MCU_SERIES := stm32f1
MCU_F1_LINE := value
LD_MEM_DIR := sram_8k_flash_128k

View File

@@ -0,0 +1,15 @@
MCU := STM32F103C8
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOB
ERROR_LED_PIN := 2
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
# This crap is due to ld-script limitations. If you know of a better
# way to go about this (like some magic ld switches to specify MEMORY
# at the command line), please tell us!
ifeq ($(BOOTLOADER),maple)
LD_MEM_DIR := sram_20k_flash_128k
endif
ifeq ($(BOOTLOADER),robotis)
LD_MEM_DIR := sram_20k_flash_128k_robotis
endif

View File

@@ -0,0 +1,10 @@
MCU := STM32F103RB
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOA
ERROR_LED_PIN := 5
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
# This crap is due to ld-script limitations. If you know of a better
# way to go about this (like some magic ld switches to specify MEMORY
# at the command line), please tell us!
LD_MEM_DIR := sram_20k_flash_128k

View File

@@ -0,0 +1,7 @@
MCU := STM32F103RE
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOA
ERROR_LED_PIN := 5
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
LD_MEM_DIR := sram_64k_flash_512k

View File

@@ -0,0 +1,7 @@
MCU := STM32F103CB
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOB
ERROR_LED_PIN := 1
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
LD_MEM_DIR := sram_20k_flash_128k

View File

@@ -0,0 +1,7 @@
MCU := STM32F103ZE
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOC
ERROR_LED_PIN := 15
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
LD_MEM_DIR := maple_native # The SRAM chip makes this board special

View File

@@ -0,0 +1,7 @@
MCU := STM32F103RB
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOC
ERROR_LED_PIN := 12
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
LD_MEM_DIR := sram_20k_flash_128k

View File

@@ -0,0 +1,15 @@
MCU := STM32F103CB
PRODUCT_ID := 0003
ERROR_LED_PORT := GPIOB
ERROR_LED_PIN := 9
MCU_SERIES := stm32f1
MCU_F1_LINE := performance
# This crap is due to ld-script limitations. If you know of a better
# way to go about this (like some magic ld switches to specify MEMORY
# at the command line), please tell us!
ifeq ($(BOOTLOADER),maple)
LD_MEM_DIR := sram_20k_flash_128k
endif
ifeq ($(BOOTLOADER),robotis)
LD_MEM_DIR := sram_20k_flash_128k_robotis
endif

View File

@@ -0,0 +1,5 @@
MCU := STM32F207IG
ERROR_LED_PORT := GPIOG
ERROR_LED_PIN := 6
MCU_SERIES := stm32f2
LD_MEM_DIR := sram_112k_flash_1024k

View File

@@ -0,0 +1,59 @@
# Useful tools
CROSS_COMPILE ?= arm-none-eabi-
CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
LD := $(CROSS_COMPILE)ld -v
AR := $(CROSS_COMPILE)ar
AS := $(CROSS_COMPILE)gcc
OBJCOPY := $(CROSS_COMPILE)objcopy
DISAS := $(CROSS_COMPILE)objdump
OBJDUMP := $(CROSS_COMPILE)objdump
SIZE := $(CROSS_COMPILE)size
DFU ?= dfu-util
# Suppress annoying output unless V is set
ifndef V
SILENT_CC = @echo ' [CC] ' $(@:$(BUILD_PATH)/%.o=%.c);
SILENT_AS = @echo ' [AS] ' $(@:$(BUILD_PATH)/%.o=%.S);
SILENT_CXX = @echo ' [CXX] ' $(@:$(BUILD_PATH)/%.o=%.cpp);
SILENT_LD = @echo ' [LD] ' $(@F);
SILENT_AR = @echo ' [AR] '
SILENT_OBJCOPY = @echo ' [OBJCOPY] ' $(@F);
SILENT_DISAS = @echo ' [DISAS] ' $(@:$(BUILD_PATH)/%.bin=%).disas;
SILENT_OBJDUMP = @echo ' [OBJDUMP] ' $(OBJDUMP);
endif
# Extra build configuration
BUILDDIRS :=
TGT_BIN :=
CFLAGS = $(GLOBAL_CFLAGS) $(TGT_CFLAGS)
CXXFLAGS = $(GLOBAL_CXXFLAGS) $(TGT_CXXFLAGS)
ASFLAGS = $(GLOBAL_ASFLAGS) $(TGT_ASFLAGS)
# Hacks to determine extra libraries we need to link against based on
# the toolchain. The default specifies no extra libraries, but it can
# be overridden.
LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/generic
ifneq ($(findstring ARM/embedded,$(shell $(CC) --version)),)
# GCC ARM Embedded, https://launchpad.net/gcc-arm-embedded/
LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded
endif
ifneq ($(findstring Linaro GCC,$(shell $(CC) --version)),)
# Summon/Linaro GCC ARM Embedded, https://github.com/esden/summon-arm-toolchain
LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded
endif
# Add toolchain directory to LD search path
TOOLCHAIN_LDFLAGS := -L $(LD_TOOLCHAIN_PATH)
# General directory independent build rules, generate dependency information
$(BUILD_PATH)/%.o: %.c
$(SILENT_CC) $(CC) $(CFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<
$(BUILD_PATH)/%.o: %.cpp
$(SILENT_CXX) $(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<
$(BUILD_PATH)/%.o: %.S
$(SILENT_AS) $(AS) $(ASFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<

View File

@@ -0,0 +1,5 @@
define LIBMAPLE_MODULE_template
dir := $(1)
include $$(dir)/rules.mk
endef

View File

@@ -0,0 +1,18 @@
sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
$(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
$(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
$(OBJS_$(d)): TGT_CXXFLAGS := $(CXXFLAGS_$(d))
$(OBJS_$(d)): TGT_ASFLAGS := $(ASFLAGS_$(d))
TGT_BIN += $(OBJS_$(d))
-include $(DEPS_$(d))
d := $(dirstack_$(sp))
sp := $(basename $(sp))

View File

@@ -0,0 +1,4 @@
sp := $(sp).x
dirstack_$(sp) := $(d)
d := $(dir)
BUILDDIRS += $(BUILD_PATH)/$(d)

View File

@@ -0,0 +1,54 @@
# TARGET_FLAGS are to be passed while compiling, assembling, linking.
TARGET_FLAGS :=
# TARGET_LDFLAGS go to the linker
TARGET_LDFLAGS :=
# Configuration derived from $(MEMORY_TARGET)
LD_SCRIPT_PATH := $(LDDIR)/$(MEMORY_TARGET).ld
ifeq ($(MEMORY_TARGET), ram)
VECT_BASE_ADDR := VECT_TAB_RAM
endif
ifeq ($(MEMORY_TARGET), flash)
VECT_BASE_ADDR := VECT_TAB_FLASH
endif
ifeq ($(MEMORY_TARGET), jtag)
VECT_BASE_ADDR := VECT_TAB_BASE
endif
# Pull in the board configuration file here, so it can override the
# above.
include $(BOARD_INCLUDE_DIR)/$(BOARD).mk
# Configuration derived from $(BOARD).mk
LD_SERIES_PATH := $(LDDIR)/stm32/series/$(MCU_SERIES)
LD_MEM_PATH := $(LDDIR)/stm32/mem/$(LD_MEM_DIR)
ifeq ($(MCU_SERIES), stm32f1)
# Due to the Balkanization on F1, we need to specify the line when
# making linker decisions.
LD_SERIES_PATH := $(LD_SERIES_PATH)/$(MCU_F1_LINE)
endif
ifeq ($(MCU_SERIES), stm32f1)
TARGET_FLAGS += -mcpu=cortex-m3 -march=armv7-m
endif
ifeq ($(MCU_SERIES), stm32f2)
TARGET_FLAGS += -mcpu=cortex-m3 -march=armv7-m
endif
ifeq ($(MCU_SERIES), stm32f4)
TARGET_FLAGS += -mcpu=cortex-m4 -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16
endif
TARGET_LDFLAGS += -Xlinker -T$(LD_SCRIPT_PATH) \
-L $(LD_SERIES_PATH) \
-L $(LD_MEM_PATH) \
-L $(LDDIR)
TARGET_FLAGS += -mthumb -DBOARD_$(BOARD) -DMCU_$(MCU) \
-DERROR_LED_PORT=$(ERROR_LED_PORT) \
-DERROR_LED_PIN=$(ERROR_LED_PIN) \
-D$(VECT_BASE_ADDR)
LIBMAPLE_MODULE_SERIES := $(LIBMAPLE_PATH)/$(MCU_SERIES)

View File

@@ -0,0 +1,5 @@
ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple"
ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple"

View File

@@ -0,0 +1,54 @@
#!/bin/sh
# This hack copies libmaple's source, linker scripts, and support
# libraries into the Maple IDE repository (which is expected as its
# first argument).
DEST=$1
DEST_CORES=$DEST/hardware/leaflabs/cores/maple
DEST_LIBS=$DEST/libraries
LMAPLE_SRC="LICENSE
./libmaple/*.h
./libmaple/*.c
./libmaple/*.S
./libmaple/usb/*.h
./libmaple/usb/*.c
./libmaple/usb/usb_lib/*.h
./libmaple/usb/usb_lib/*.c
./wirish/*.h
./wirish/main.cxx
./wirish/*.cpp
./wirish/comm/*.cpp
./wirish/comm/*.h
./wirish/boards/*.h
./wirish/boards/*.cpp
./support/ld/common.inc
./support/ld/maple
./support/ld/maple_mini
./support/ld/maple_native
./support/ld/maple_RET6
./support/ld/names.inc"
echo "First make sure DEST exists: $DEST"
if !(test -d $DEST)
then
echo "Nope! Make sure you're doing this right?"
exit -1
fi
# source
echo Copying libmaple source
rm -rf $DEST_CORES/*.c $DEST_CORES/*.cpp $DEST_CORES/*.h $DEST_CORES/*.cxx $DEST_CORES/*.S
rm -rf $DEST_CORES/*.inc $DEST_CORES/*.a $DEST_CORES/maple $DEST_CORES/maple_*
cp -R $LMAPLE_SRC $DEST_CORES
echo Copying over libraries
cp -R libraries/* $DEST_LIBS
# libmaple version
echo Creating libmaple-version.txt
git show-ref HEAD | cut -c 1-10 > $DEST/libmaple-version.txt
echo Done.

View File

@@ -0,0 +1,145 @@
#!/usr/bin/env python
from __future__ import print_function
import serial
import os
import platform
import sys
import time
from struct import pack
def unix_get_maple_path(file_prefix, dev_is_maple=lambda dev: True):
"""Try to find the device file for the Maple on *nix.
This function works assuming that the device file globs like
'/dev/<file_prefix>*'. The caller may pass an additional
dev_is_maple predicate if the platform supports additional tests
to determine if a device is a Maple.
If there are multiple possibilities, ask the user what to do. If
the user chooses not to say, returns None."""
possible_paths = [os.path.join('/dev', x) for x in os.listdir('/dev') \
if x.startswith(file_prefix) and dev_is_maple(x)]
return choose_path(possible_paths)
def linux_get_maple_path(file_prefix='ttyACM'):
"""Specialized unix_get_maple_path() for Linux.
Attempts to check that a candidate device has the correct ID in
the /sys tree when deciding if it's a Maple."""
return unix_get_maple_path(file_prefix, linux_tty_is_maple)
def linux_tty_is_maple(device):
try:
sysfile = open("/sys/class/tty/%s/device/uevent" % device, "r")
text = "".join(sysfile.readlines())
return "PRODUCT=1eaf/4" in text
except IOError: # no udev info available
return True
def windows_get_maple_path():
"""Similar to unix_get_maple_path(), but on Windows."""
import _winreg as reg
p = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
k = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, p)
possible_paths = []
i = 0
while True:
try:
possible_paths.append(reg.EnumValue(k, i)[1])
i += 1
except WindowsError:
break
return choose_path(possible_paths)
def choose_path(possible_paths):
if len(possible_paths) == 0:
return None
elif len(possible_paths) == 1:
return possible_paths[0]
else:
print('Found multiple candidates for the Maple device:')
return choose_among_options(possible_paths)
def choose_among_options(options):
for (i,p) in enumerate(options):
print('\t%d. %s' % (i+1, p))
prompt = 'Enter a number to select one, or q to quit: '
while True:
resp = raw_input(prompt).strip().lower()
if resp == 'q': sys.exit()
try:
i = int(resp, 10)
except ValueError:
pass
else:
if 0 <= i-1 < len(options):
return options[i-1]
prompt = 'Please enter a number from the list, or q to quit: '
plat_sys = platform.system()
plat_bits = platform.architecture()[0]
if plat_sys == 'Linux':
maple_path = linux_get_maple_path()
# fall back on /dev/maple if that doesn't work
if maple_path is None:
maple_path = '/dev/maple'
print('Could not find Maple serial port; defaulting to /dev/maple.')
elif plat_sys == 'Darwin':
maple_path = unix_get_maple_path('tty.usbmodem')
elif plat_sys == 'Windows':
maple_path = windows_get_maple_path()
else:
maple_path = raw_input('Unrecognized platform. Please enter '
"the path to the Maple's serial port device file:")
if maple_path is None:
print('Could not find the Maple serial port for reset.',
'Perhaps this is your first upload, or the board is already',
'in bootloader mode.')
print()
print("If your sketch doesn't upload, try putting your Maple",
'into bootloader mode manually by pressing the RESET button',
'then letting it go and quickly pressing button BUT',
'(hold for several seconds).')
sys.exit()
print('Using %s as Maple serial port' % maple_path)
try:
ser = serial.Serial(maple_path, baudrate=115200, xonxoff=1)
try:
# try to toggle DTR/RTS (old scheme)
ser.setRTS(0)
time.sleep(0.01)
ser.setDTR(0)
time.sleep(0.01)
ser.setDTR(1)
time.sleep(0.01)
ser.setDTR(0)
# try magic number
ser.setRTS(1)
time.sleep(0.01)
ser.setDTR(1)
time.sleep(0.01)
ser.setDTR(0)
time.sleep(0.01)
ser.write("1EAF".encode("ascii"))
ser.flush()
# Delay a bit before proceeding
time.sleep(0.1)
finally:
# ok we're done here
ser.close()
except Exception as e:
print('Failed to open serial port %s for reset' % maple_path)
sys.exit()

View File

@@ -0,0 +1,94 @@
#!/usr/bin/python
# This script sends a program on a robotis board (OpenCM9.04 or CM900)
# using the robotis bootloader (used in OpenCM IDE)
#
# Usage:
# python robotis-loader.py <serial port> <binary>
#
# Example:
# python robotis-loader.py /dev/ttyACM0 firmware.bin
#
# https://github.com/Gregwar/robotis-loader
import serial, sys, os, time
print('~~ Robotis loader ~~')
print('')
# Reading command line
if len(sys.argv) != 3:
exit('! Usage: robotis-loader.py <serial-port> <binary>')
pgm, port, binary = sys.argv
# Helper to prints a progress bar
def progressBar(percent, precision=65):
threshold=precision*percent/100.0
sys.stdout.write('[ ')
for x in xrange(0, precision):
if x < threshold: sys.stdout.write('#')
else: sys.stdout.write(' ')
sys.stdout.write(' ] ')
sys.stdout.flush()
# Opening the firmware file
try:
stat = os.stat(binary)
size = stat.st_size
firmware = file(binary, 'rb')
print('* Opening %s, size=%d' % (binary, size))
except:
exit('! Unable to open file %s' % binary)
# Opening serial port
try:
s = serial.Serial(port, baudrate=115200)
except:
exit('! Unable to open serial port %s' % port)
print('* Resetting the board')
s.setRTS(True)
s.setDTR(False)
time.sleep(0.1)
s.setRTS(False)
s.write('CM9X')
s.close()
time.sleep(1.0);
print('* Connecting...')
s = serial.Serial(port, baudrate=115200)
s.write('AT&LD')
print('* Download signal transmitted, waiting...')
# Entering bootloader sequence
while True:
line = s.readline().strip()
if line.endswith('Ready..'):
print('* Board ready, sending data')
cs = 0
pos = 0
while True:
c = firmware.read(2048)
if len(c):
pos += len(c)
sys.stdout.write("\r")
progressBar(100*float(pos)/float(size))
s.write(c)
for k in range(0,len(c)):
cs = (cs+ord(c[k]))%256
else:
break
print('')
s.setDTR(True)
print('* Checksum: %d' % (cs))
s.write(chr(cs))
print('* Firmware was sent')
else:
if line == 'Success..':
print('* Success, running the code')
print('')
s.write('AT&RST')
s.close()
exit()
else:
print('Board -> '+line)

View File

@@ -0,0 +1,29 @@
# Windows program for listing COM (serial) ports.
#
# enumerate_serial_ports() is by Eli Bendersky:
#
# http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
import _winreg as winreg
import itertools
def enumerate_serial_ports():
""" Uses the Win32 registry to return an
iterator of serial (COM) ports
existing on this computer.
"""
path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
except WindowsError:
raise IterationError
for i in itertools.count():
try:
val = winreg.EnumValue(key, i)
yield str(val[1])
except EnvironmentError:
break
for com in enumerate_serial_ports():
print com

View File

@@ -0,0 +1,532 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: sw=4:ts=4:si:et:enc=utf-8
# Author: Ivan A-R <ivan@tuxotronic.org>
# Project page: http://tuxotronic.org/wiki/projects/stm32loader
#
# This file is part of stm32loader.
#
# stm32loader is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# stm32loader is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with stm32loader; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys, getopt
import serial
import time
import glob
import time
import tempfile
import os
import subprocess
try:
from progressbar import *
usepbar = 1
except:
usepbar = 0
# Verbose level
QUIET = 5
def mdebug(level, message):
if QUIET >= level:
print(message, file=sys.stderr)
# Takes chip IDs (obtained via Get ID command) to human-readable names
CHIP_ID_STRS = {0x410: 'STM32F1, performance, medium-density',
0x411: 'STM32F2',
0x412: 'STM32F1, performance, low-density',
0x413: 'STM32F4',
0x414: 'STM32F1, performance, high-density',
0x416: 'STM32L1, performance, medium-density',
0x418: 'STM32F1, connectivity',
0x420: 'STM32F1, value, medium-density',
0x428: 'STM32F1, value, high-density',
0x430: 'STM32F1, performance, XL-density'}
class CmdException(Exception):
pass
class CommandInterface(object):
def open(self, aport='/dev/tty.usbserial-FTD3TMCH', abaudrate=115200) :
self.sp = serial.Serial(
port=aport,
baudrate=abaudrate, # baudrate
bytesize=8, # number of databits
parity=serial.PARITY_EVEN,
stopbits=1,
xonxoff=0, # enable software flow control
rtscts=0, # disable RTS/CTS flow control
timeout=0.5 # set a timeout value, None for waiting forever
)
def _wait_for_ack(self, info="", timeout=0):
stop = time.time() + timeout
got = None
while not got:
got = self.sp.read(1)
if time.time() > stop:
break
if not got:
raise CmdException("No response to %s" % info)
# wait for ask
ask = ord(got)
if ask == 0x79:
# ACK
return 1
elif ask == 0x1F:
# NACK
raise CmdException("Chip replied with a NACK during %s" % info)
# Unknown response
raise CmdException("Unrecognised response 0x%x to %s" % (ask, info))
def reset(self):
self.sp.setDTR(0)
time.sleep(0.1)
self.sp.setDTR(1)
time.sleep(0.5)
def initChip(self):
# Set boot
self.sp.setRTS(0)
self.reset()
# Be a bit more persistent when trying to initialise the chip
stop = time.time() + 5.0
while time.time() <= stop:
self.sp.write('\x7f')
got = self.sp.read()
# The chip will ACK a sync the very first time and
# NACK it every time afterwards
if got and got in '\x79\x1f':
# Synced up
return
raise CmdException('No response while trying to sync')
def releaseChip(self):
self.sp.setRTS(1)
self.reset()
def cmdGeneric(self, cmd):
self.sp.write(chr(cmd))
self.sp.write(chr(cmd ^ 0xFF)) # Control byte
return self._wait_for_ack(hex(cmd))
def cmdGet(self):
if self.cmdGeneric(0x00):
mdebug(10, "*** Get command");
len = ord(self.sp.read())
version = ord(self.sp.read())
mdebug(10, " Bootloader version: "+hex(version))
dat = map(lambda c: hex(ord(c)), self.sp.read(len))
mdebug(10, " Available commands: "+str(dat))
self._wait_for_ack("0x00 end")
return version
else:
raise CmdException("Get (0x00) failed")
def cmdGetVersion(self):
if self.cmdGeneric(0x01):
mdebug(10, "*** GetVersion command")
version = ord(self.sp.read())
self.sp.read(2)
self._wait_for_ack("0x01 end")
mdebug(10, " Bootloader version: "+hex(version))
return version
else:
raise CmdException("GetVersion (0x01) failed")
def cmdGetID(self):
if self.cmdGeneric(0x02):
mdebug(10, "*** GetID command")
len = ord(self.sp.read())
id = self.sp.read(len+1)
self._wait_for_ack("0x02 end")
return id
else:
raise CmdException("GetID (0x02) failed")
def _encode_addr(self, addr):
byte3 = (addr >> 0) & 0xFF
byte2 = (addr >> 8) & 0xFF
byte1 = (addr >> 16) & 0xFF
byte0 = (addr >> 24) & 0xFF
crc = byte0 ^ byte1 ^ byte2 ^ byte3
return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3) + chr(crc))
def cmdReadMemory(self, addr, lng):
assert(lng <= 256)
if self.cmdGeneric(0x11):
mdebug(10, "*** ReadMemory command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ack("0x11 address failed")
N = (lng - 1) & 0xFF
crc = N ^ 0xFF
self.sp.write(chr(N) + chr(crc))
self._wait_for_ack("0x11 length failed")
return map(lambda c: ord(c), self.sp.read(lng))
else:
raise CmdException("ReadMemory (0x11) failed")
def cmdGo(self, addr):
if self.cmdGeneric(0x21):
mdebug(10, "*** Go command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ack("0x21 go failed")
else:
raise CmdException("Go (0x21) failed")
def cmdWriteMemory(self, addr, data):
assert(len(data) <= 256)
if self.cmdGeneric(0x31):
mdebug(10, "*** Write memory command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ack("0x31 address failed")
#map(lambda c: hex(ord(c)), data)
lng = (len(data)-1) & 0xFF
mdebug(10, " %s bytes to write" % [lng+1]);
self.sp.write(chr(lng)) # len really
crc = 0xFF
for c in data:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ack("0x31 programming failed")
mdebug(10, " Write memory done")
else:
raise CmdException("Write memory (0x31) failed")
def cmdEraseMemory(self, sectors = None):
if self.cmdGeneric(0x43):
mdebug(10, "*** Erase memory command")
if sectors is None:
# Global erase
self.sp.write(chr(0xFF))
self.sp.write(chr(0x00))
else:
# Sectors erase
self.sp.write(chr((len(sectors)-1) & 0xFF))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ack("0x43 erasing failed")
mdebug(10, " Erase memory done")
else:
raise CmdException("Erase memory (0x43) failed")
# TODO support for non-global mass erase
GLOBAL_ERASE_TIMEOUT_SECONDS = 20 # This takes a while
def cmdExtendedEraseMemory(self):
if self.cmdGeneric(0x44):
mdebug(10, "*** Extended erase memory command")
# Global mass erase
mdebug(5, "Global mass erase; this may take a while")
self.sp.write(chr(0xFF))
self.sp.write(chr(0xFF))
# Checksum
self.sp.write(chr(0x00))
self._wait_for_ack("0x44 extended erase failed",
timeout=self.GLOBAL_ERASE_TIMEOUT_SECONDS)
mdebug(10, " Extended erase memory done")
else:
raise CmdException("Extended erase memory (0x44) failed")
def cmdWriteProtect(self, sectors):
if self.cmdGeneric(0x63):
mdebug(10, "*** Write protect command")
self.sp.write(chr((len(sectors)-1) & 0xFF))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ack("0x63 write protect failed")
mdebug(10, " Write protect done")
else:
raise CmdException("Write Protect memory (0x63) failed")
def cmdWriteUnprotect(self):
if self.cmdGeneric(0x73):
mdebug(10, "*** Write Unprotect command")
self._wait_for_ack("0x73 write unprotect failed")
self._wait_for_ack("0x73 write unprotect 2 failed")
mdebug(10, " Write Unprotect done")
else:
raise CmdException("Write Unprotect (0x73) failed")
def cmdReadoutProtect(self):
if self.cmdGeneric(0x82):
mdebug(10, "*** Readout protect command")
self._wait_for_ack("0x82 readout protect failed")
self._wait_for_ack("0x82 readout protect 2 failed")
mdebug(10, " Read protect done")
else:
raise CmdException("Readout protect (0x82) failed")
def cmdReadoutUnprotect(self):
if self.cmdGeneric(0x92):
mdebug(10, "*** Readout Unprotect command")
self._wait_for_ack("0x92 readout unprotect failed")
self._wait_for_ack("0x92 readout unprotect 2 failed")
mdebug(10, " Read Unprotect done")
else:
raise CmdException("Readout unprotect (0x92) failed")
# Complex commands section
def readMemory(self, addr, lng):
data = []
if usepbar:
widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
else:
mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
data = data + self.cmdReadMemory(addr, 256)
addr = addr + 256
lng = lng - 256
if usepbar:
pbar.update(pbar.maxval-lng)
pbar.finish()
else:
mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
data = data + self.cmdReadMemory(addr, lng)
return data
def writeMemory(self, addr, data):
lng = len(data)
mdebug(5, "Writing %(lng)d bytes to start address 0x%(addr)X" %
{ 'lng': lng, 'addr': addr})
if usepbar:
widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
offs = 0
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
else:
mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
self.cmdWriteMemory(addr, data[offs:offs+256])
offs = offs + 256
addr = addr + 256
lng = lng - 256
if usepbar:
pbar.update(pbar.maxval-lng)
pbar.finish()
else:
mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
self.cmdWriteMemory(addr, data[offs:offs+lng] + ([0xFF] * (256-lng)) )
def usage():
print("""Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [file.bin]
-h This help
-q Quiet
-V Verbose
-e Erase
-w Write
-v Verify
-r Read
-l length Length of read
-p port Serial port (default: first USB-like port in /dev)
-b baud Baud speed (default: 115200)
-a addr Target address
./stm32loader.py -e -w -v example/main.bin
""" % sys.argv[0])
def read(filename):
"""Read the file to be programmed and turn it into a binary"""
with open(filename, 'rb') as f:
bytes = f.read()
if bytes.startswith('\x7FELF'):
# Actually an ELF file. Convert to binary
handle, path = tempfile.mkstemp(suffix='.bin', prefix='stm32loader')
try:
os.close(handle)
# Try a couple of options for objcopy
for name in ['arm-none-eabi-objcopy', 'arm-linux-gnueabi-objcopy']:
try:
code = subprocess.call([name, '-Obinary', filename, path])
if code == 0:
return read(path)
except OSError:
pass
else:
raise Exception('Error %d while converting to a binary file' % code)
finally:
# Remove the temporary file
os.unlink(path)
else:
return [ord(x) for x in bytes]
if __name__ == "__main__":
conf = {
'port': 'auto',
'baud': 115200,
'address': 0x08000000,
'erase': 0,
'write': 0,
'verify': 0,
'read': 0,
'len': 1000,
'fname':'',
}
# http://www.python.org/doc/2.5.2/lib/module-getopt.html
try:
opts, args = getopt.getopt(sys.argv[1:], "hqVewvrp:b:a:l:")
except getopt.GetoptError as err:
# print help information and exit:
print(str(err)) # will print something like "option -a not recognized"
usage()
sys.exit(2)
for o, a in opts:
if o == '-V':
QUIET = 10
elif o == '-q':
QUIET = 0
elif o == '-h':
usage()
sys.exit(0)
elif o == '-e':
conf['erase'] = 1
elif o == '-w':
conf['write'] = 1
elif o == '-v':
conf['verify'] = 1
elif o == '-r':
conf['read'] = 1
elif o == '-p':
conf['port'] = a
elif o == '-b':
conf['baud'] = eval(a)
elif o == '-a':
conf['address'] = eval(a)
elif o == '-l':
conf['len'] = eval(a)
else:
assert False, "unhandled option"
# Try and find the port automatically
if conf['port'] == 'auto':
ports = []
# Get a list of all USB-like names in /dev
for name in ['tty.usbserial', 'ttyUSB']:
ports.extend(glob.glob('/dev/%s*' % name))
ports = sorted(ports)
if ports:
# Found something - take it
conf['port'] = ports[0]
cmd = CommandInterface()
cmd.open(conf['port'], conf['baud'])
mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'],
'baud':conf['baud']})
try:
if (conf['write'] or conf['verify']):
mdebug(5, "Reading data from %s" % args[0])
data = read(args[0])
try:
cmd.initChip()
except CmdException:
print("Can't init. Ensure BOOT0=1, BOOT1=0, and reset device")
bootversion = cmd.cmdGet()
mdebug(0, "Bootloader version 0x%X" % bootversion)
if bootversion < 20 or bootversion >= 100:
raise Exception('Unreasonable bootloader version %d' % bootversion)
chip_id = cmd.cmdGetID()
assert len(chip_id) == 2, "Unreasonable chip id: %s" % repr(chip_id)
chip_id_num = (ord(chip_id[0]) << 8) | ord(chip_id[1])
chip_id_str = CHIP_ID_STRS.get(chip_id_num, None)
if chip_id_str is None:
mdebug(0, 'Warning: unrecognised chip ID 0x%x' % chip_id_num)
else:
mdebug(0, "Chip id 0x%x, %s" % (chip_id_num, chip_id_str))
if conf['erase']:
# Pre-3.0 bootloaders use the erase memory
# command. Starting with 3.0, extended erase memory
# replaced this command.
if bootversion < 0x30:
cmd.cmdEraseMemory()
else:
cmd.cmdExtendedEraseMemory()
if conf['write']:
cmd.writeMemory(conf['address'], data)
if conf['verify']:
verify = cmd.readMemory(conf['address'], len(data))
if(data == verify):
print("Verification OK")
else:
print("Verification FAILED")
print(str(len(data)) + ' vs ' + str(len(verify)))
for i in xrange(0, len(data)):
if data[i] != verify[i]:
print(hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i]))
if not conf['write'] and conf['read']:
rdata = cmd.readMemory(conf['address'], conf['len'])
file(args[0], 'wb').write(''.join(map(chr,rdata)))
finally:
cmd.releaseChip()