+*.o
+read-rom
+mass-erase
+led-test
+.PHONY: all
+all: read-rom mass-erase led-test
+
+%.o: %.s
+ arm-none-eabi-as -g -c $< -o $@
+
+%.o: %.c
+ arm-none-eabi-gcc -march=armv6-m -O2 -g -c $< -o $@
+
+read-rom: read-rom.o
+ arm-none-eabi-ld -T memory-ram.x $^ -o $@
+
+mass-erase: mass-erase.o
+ arm-none-eabi-ld -T memory-ram.x $^ -o $@
+
+led-test: crt0.o led-bits.o led-test.o
+ arm-none-eabi-ld -T memory-flash.x $^ /usr/lib/gcc/arm-none-eabi/10.3.1/thumb/v6-m/nofp/libgcc.a -o $@
+.section .vectors, "ax"
+.align 2
+.global __vectors, __VECTOR_TABLE
+__VECTOR_TABLE:
+__vectors:
+.word __StackTop
+.word _start
+.word _end // NMI
+.word _end // HardFault
+.word _end // Reserved
+.word _end // Reserved
+.word _end // Reserved
+.word _end // Reserved
+.word _end // Reserved
+.word _end // Reserved
+.word _end // Reserved
+.word _end // SVCall
+.word _end // Reserved
+.word _end // Reserved
+.word _end // PendSV
+.word _end // SysTick
+.word _end // LVD
+.word _end // RTC
+.word _end // FMC
+.word _end // WKUP
+.word _end // EXTI0-1
+.word _end // EXTI2-3
+.word _end // EXTI4-15
+.word _end // CMP
+.word _end // ADC
+.word _end // Reserved
+.word _end // MCTM
+.word _end // GPTM1
+.word _end // GPTM0
+.word _end // SCTM0
+.word _end // SCTM1
+.word _end // Reserved
+.word _end // Reserved
+.word _end // BFTM0
+.word _end // BFTM1
+.word _end // I2C0
+.word _end // I2C1
+.word _end // SPI0
+.word _end // SPI1
+.word _end // USART0
+.word _end // USART1
+.word _end // UART0
+.word _end // UART1
+.word _end // SCI0-1
+.word _end // I2S
+.word _end // USB
+.word _end // PDMA_CH0-1
+.word _end // PDMA_CH2-5
+
+.text
+
+.type _start,%function
+.thumb_func
+.global _start
+_start:
+ ldr r0, =__stack
+ mov sp, r0
+ b main
+.thumb_func
+_end:
+ b _end
+
+.align
+.pool
+.thumb
+
+.global sendword
+sendword:
+ push {r4, r5, r6}
+ mov r1, #1
+ lsl r1, #23 // r1 - bit mask
+ ldr r3, =0x400b2024 // PORTB Set/Reset register
+ mov r4, #1
+ lsl r4, #16 // r4 - set
+ mov r5, #1 // r5 - reset (inverted due to output MOSFET driver)
+ mov r6, #24 // r6 - bit counter
+ b 2f
+1:
+ sub r6, #1
+ beq 4f
+ lsl r0, #1
+2:
+ mov r2, r0
+ and r2, r1
+ beq 3f
+ // 1 bit
+ str r4, [r3] // set
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ str r5, [r3] // reset
+ b 1b
+3:
+ str r4, [r3]
+ nop
+ nop
+ nop
+ nop
+ str r5, [r3]
+ nop
+ nop
+ nop
+ nop
+ b 1b
+4:
+ pop {r4, r5, r6}
+ bx lr
+#include <stdint.h>
+
+#define CKCU_BASE 0x40088000
+#define AHBCCR 0x24
+#define GPIOB_BASE 0x400b2000
+#define DIRCR 0x000 // Port A Data Direction Control Register
+#define INER 0x004 // Port A Input Function Enable Control Register
+#define PUR 0x008 // Port A Pull-Up Selection Register
+#define PDR 0x00C // Port A Pull-Down Selection Register
+#define ODR 0x010 // Port A Open Drain Selection Register
+#define DRVR 0x014 // Port A Drive Current Selection Register
+#define LOCKR 0x018 // Port A Lock Register
+#define DINR 0x01C // Port A Data Input Register
+#define DOUTR 0x020 // Port A Data Output Register
+#define SRR 0x024 // Port A Output Set and Reset Control Register
+#define RR 0x028 // Port A Output Reset Control Register
+
+#define LED_D_OFF (*(uint32_t*)(GPIOB_BASE + SRR) = 1)
+#define LED_D_ON (*(uint32_t*)(GPIOB_BASE + SRR) = 1 << 16)
+
+void sendword(uint32_t w);
+
+void delay(int n) {
+ n <<= 4;
+ for (int i = 0; i < n; i++) {
+ __asm__("nop");
+ }
+}
+
+void reset() {
+ LED_D_OFF;
+ delay(100);
+}
+
+// a * (c / 255) + b * ((255 - c) / 255)
+uint32_t lerp(uint32_t a, uint32_t b, uint8_t c) {
+ uint8_t* aa = (uint8_t*)&a;
+ uint8_t* bb = (uint8_t*)&b;
+ uint32_t r;
+ uint8_t* rr = (uint8_t*)&r;
+
+ for (int i = 0; i < 3; i++) {
+ uint32_t ac = ((uint32_t)aa[i] * c) / 255;
+ uint32_t bc = ((uint64_t)bb[i] * (255 - c)) / 255;
+ rr[i] = (uint8_t)ac + bc;
+ }
+ return r;
+}
+
+void main() {
+ // Enable GPIOB peripheral
+ *(uint32_t*)(CKCU_BASE + AHBCCR) |= 0x00020000;
+ // Enable output direction on B0
+ *(uint32_t*)(GPIOB_BASE + DIRCR) = 1;
+
+ uint8_t j = 0;
+ uint32_t values[15];
+ while (1) {
+ for (int i = 0; i < 15; i++) {
+ //values[i] = lerp(0x002020, 0x400000, (j + i * 10) % 255);
+ values[i] = (i % 2) ^ (j < 128) ? (j < 128 ? 0x000f0f : 0x1e0000) : 0x000000;
+ }
+ for (int i = 0; i < 15; i++) {
+ sendword(values[i]);
+ }
+ delay(1000);
+ j += 5;
+ }
+}
+.text
+.thumb
+
+.global _start
+_start:
+ ldr r0, OCMR
+ ldr r1, OPCR
+ bl idle_check
+
+ mov r2, #0xA
+ str r2, [r0] // store 0xA in OCMR
+ lsl r2, #1 // Shift left into OPM location
+ str r2, [r1] // store 0xa in OPCR.OPM
+
+ bl idle_check
+
+end:
+ b end
+
+idle_check:
+ mov r3, #8 // Compare bit 3
+1:
+ ldr r2, [r1] // load OPCR
+ and r2, r3 // If bit 3 is clear,
+ beq 1b // a flash operation is in progress
+ bx lr
+
+.align
+OCMR: .word 0x4008000c
+OPCR: .word 0x40080010
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ FLASH(rx) : ORIGIN = 0x00000000, LENGTH = 128k
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 16k
+}
+
+ENTRY(_start)
+
+SECTIONS
+{
+ .text : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.reset))
+ /* TODO revisit this now memset/memcpy/float in ROM */
+ /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+ * FLASH ... we will include any thing excluded here in .data below by default */
+ *(.init)
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ } > FLASH
+
+ .rodata : {
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ .ram_vector_table (NOLOAD): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM AT> FLASH
+ /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+ __etext = LOADADDR(.data);
+
+ .uninitialized_data (NOLOAD): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (NOLOAD):
+ {
+ __end__ = .;
+ end = __end__;
+ KEEP(*(.heap*))
+ __HeapLimit = .;
+ } > RAM
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackTop = __StackLimit;
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 16k
+}
+
+ENTRY(_start)
+
+SECTIONS
+{
+ /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
+ entry (ELF entry point), are *first* in the image, and the vector table
+ follows immediately afterward. This is because the bootrom enters RAM
+ binaries directly at their lowest address (preferring main RAM over XIP
+ cache-as-SRAM if both are used).
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ __reset_start = .;
+ KEEP (*(.reset))
+ __reset_end = .;
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ . = ALIGN(256);
+ KEEP (*(.vectors))
+ *(.time_critical*)
+ *(.text*)
+ . = ALIGN(4);
+ *(.init)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ } > RAM
+
+ .rodata : {
+ *(.rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > RAM
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > RAM
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > RAM
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > RAM
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM
+
+ .uninitialized_data (NOLOAD): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+ /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+ __etext = LOADADDR(.data);
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (NOLOAD):
+ {
+ __end__ = .;
+ end = __end__;
+ KEEP(*(.heap*))
+ __HeapLimit = .;
+ } > RAM
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackTop = __StackLimit;
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
+.text
+.thumb
+
+.global _start
+_start:
+ movs r0, #1
+ lsl r0, #13
+ ldr r1, RAM
+ mov r2, #1
+ lsl r2, #13
+loop:
+ ldr r3, [r0, r2]
+ str r3, [r1, r2]
+ sub r2, #4
+ bne loop
+end:
+ b end
+
+.align
+RAM: .word 0x20001000
+GPIO_A: .word 0x400b0000