aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-13 23:05:32 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-11-13 23:05:32 -0700
commitc9402e5a5d67ef877fa7f5f67c07a794574ded35 (patch)
treeaad50c7d861f3f4c68d985abe1b8fce79d10bc86
parentda45a7210ef634fcdb0270bffc90d4da97c61230 (diff)
downloadch573-c9402e5a5d67ef877fa7f5f67c07a794574ded35.tar.gz
ch573-c9402e5a5d67ef877fa7f5f67c07a794574ded35.tar.bz2
ch573-c9402e5a5d67ef877fa7f5f67c07a794574ded35.zip
Added a whole bunch of fiddle files. Started improving boot process.
It still works.
-rw-r--r--CMakeLists.txt12
-rw-r--r--fdl/ch573/clock.fdl209
-rw-r--r--fdl/ch573/common.fdl17
-rw-r--r--fdl/ch573/gpio.fdl219
-rw-r--r--fdl/ch573/spi.fdl158
-rw-r--r--fdl/ch573/uart.fdl157
-rw-r--r--include/isr_vector.h81
-rw-r--r--linker/ls.ld23
-rw-r--r--src/blinky.c134
-rw-r--r--src/init.c143
10 files changed, 1091 insertions, 62 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8c26a3..09a39d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+include(cmake/fiddle.cmake)
+
project (ch537)
# Configure for Bare Metal.
@@ -8,9 +10,9 @@ set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR riscv32)
set(TC_PREFIX riscv32-unknown-elf-)
-include_directories(include linker)
+include_directories(include linker ${CMAKE_BINARY_DIR}/generated/fdl)
-file(GLOB SOURCES "src/*.c")
+file(GLOB SOURCES "src/*.c" "src/*.s")
file(GLOB LINKER_SCRIPT "linker/*.ld")
file(REAL_PATH "ch-flash/" CH_FLASH_DIR)
@@ -27,6 +29,7 @@ set(CMAKE_EXE_LINKER_FLAGS "--xref -static -T ${LINKER_SCRIPT}" CACHE INTERNAL "
# Add executable with custom linking commands
add_executable(main.elf ${SOURCES})
+add_dependencies(main.elf fdl_headers)
# Replace default link command to use `ld` directly without `-Wl,` prefixes.
set_target_properties(main.elf PROPERTIES
@@ -36,6 +39,11 @@ set_target_properties(main.elf PROPERTIES
CMAKE_C_LINK_EXECUTABLE "${TC_PREFIX}ld <LINK_FLAGS> <OBJECTS> -o <TARGET> ${CMAKE_EXE_LINKER_FLAGS}"
)
+set(fdl_headers)
+file(GLOB_RECURSE fdl_files "${CMAKE_SOURCE_DIR}/fdl/*.fdl")
+fiddle_sources(fdl_headers "${fdl_files}")
+add_custom_target( fdl_headers DEPENDS ${fdl_headers})
+
# Generates the binary with objcopy.
add_custom_command(
OUTPUT main.bin
diff --git a/fdl/ch573/clock.fdl b/fdl/ch573/clock.fdl
new file mode 100644
index 0000000..c550d76
--- /dev/null
+++ b/fdl/ch573/clock.fdl
@@ -0,0 +1,209 @@
+import "ch573/common.fdl";
+
+/** Package for the system clock registers. */
+package ch573.clock {
+ location clock_base = 0x4000_1000;
+
+ using ch573.common;
+
+ type clock_cfg_t : struct {
+ skip_to(0x08);
+
+ assert_pos(0x08);
+ /** System clock configuration register */
+ reg clk_sys_cfg(16) : struct {
+ clk_pll_div : (5);
+ reserved(1);
+ /** The system clock source. */
+ clk_sys_mod : enum(2) {
+ /** 32 Mhz external clock source. */
+ [[ c: unqualified ]]
+ HCLK_SRC_CK32M = 0b00,
+
+ /** PLL clock source.*/
+ [[ c: unqualified ]]
+ HCLK_SRC_PLL = 0b01,
+
+ /** 32kHz internal clock. */
+ [[ c: unqualified ]]
+ HCLK_SRC_CK32K = 0b11,
+ reserved = 0b10,
+ };
+ reserved(8);
+ };
+
+ assert_pos(0x0A);
+ /** High frequency clock module power control register */
+ reg hfck_pwr_ctrl(8) : struct {
+ reserved(2);
+ /** External oscillator on. */
+ clk_xt32m_pon : bit_t;
+ reserved(1);
+ /** PLL Power on */
+ clk_pll_pon : bit_t;
+ reserved(3);
+ };
+
+ skip_to(0x2C);
+ assert_pos(0x2C);
+ /** Internal 32KHz clock tune register */
+ reg(16) : struct {
+ int32k_tune : (12);
+ reserved(4);
+ };
+
+ assert_pos(0x2E);
+ /** External 32KHz clock resonance tune register */
+ reg xt32k_tune(8) : struct {
+ reserved(4);
+ xt32k_c_load : (4);
+ };
+
+ assert_pos(0x2F);
+ /** 32KHz oscillator configuration register */
+ reg ck32k_config(8) : struct {
+ clk_int32k_pon : enable_t;
+ clk_xt32k_pon : enable_t;
+ clk_osc32k_xt : enum(1) {
+ [[ c: unqualified ]]
+ INTERNAL_32K_OSC = 1,
+ [[ c: unqualified ]]
+ EXTERNAL_32K_OSC = 0,
+ };
+ reserved(4);
+ rb_32k_clk_pin : enable_t;
+ };
+
+ assert_pos(0x30);
+ /** RTC flag and control register */
+ reg rtc_flag_ctrl(8) : struct {
+ reserved(4);
+ rtc_tmr_clr : bit_t;
+ rtc_trig_clr : bit_t;
+ ro rtc_tmr_flag : bit_t;
+ ro rtc_trig_flag : bit_t;
+ };
+
+ assert_pos(0x31);
+ /** RTC mode configuration register */
+ reg rtc_mode_ctrl(8) : struct {
+ rtc_tmr_mode : enum(3) {
+ [[ c: unqualified ]]
+ TMR_MODE_0_125_S = 0,
+ [[ c: unqualified ]]
+ TMR_MODE_0_25_S = 1,
+ [[ c: unqualified ]]
+ TMR_MODE_0_5_S = 2,
+ [[ c: unqualified ]]
+ TMR_MODE_1_S = 3,
+ [[ c: unqualified ]]
+ TMR_MODE_2_S = 4,
+ [[ c: unqualified ]]
+ TMR_MODE_4_S = 5,
+ [[ c: unqualified ]]
+ TMR_MODE_8_S = 6,
+ [[ c: unqualified ]]
+ TMR_MODE_16_S = 7,
+ };
+
+ /** Ignore and compare the lowest bit of matching value in trigger mode: */
+ rtc_ignore_b0 : enum(1) {
+ [[ c: unqualified ]]
+ IGNORE_LOWEST_BIT = 1,
+ [[ c: unqualified ]]
+ COMPARE_LOWEST_BIT = 0,
+ };
+
+ /** Rtc Timing mode enabled. */
+ rtc_tmr_en : enable_t;
+
+ /** Rtc trigger mode enabled. */
+ rtc_trig_en : enable_t;
+
+ /** Write 1 to load the low word of RTC counter, and automatically cleared
+ * after loading. Load the high 16 bits of R32_RTC_TRIG to R16_RTC_CNT_2S;
+ * load the low 16 bits of R32_RTC_TRIG to R16_RTC_CNT_32K */
+ rtc_load_lo : enable_t;
+
+ /** Write 1 to load the high word of RTC counter, and automatically cleared
+ * to 0 after loading. Load R32_RTC_TRIG (actually only the low 14 bits) to
+ * R32_RTC_CNT_DAY. */
+ rtc_load_hi : enable_t;
+ };
+
+ skip_to(0x34);
+ assert_pos(0x34);
+ /** RTC trigger value register */
+ reg rtc_trig(32);
+
+ assert_pos(0x38);
+ /** RTC based 32768Hz count value register */
+ reg rtc_cnt_32k(16);
+
+ assert_pos(0x3A);
+ /** RTC count value register in the unit of 2S */
+ reg rtc_cnt_2s(16);
+
+ assert_pos(0x3C);
+ /** RTC count value register in the unit of day */
+ reg (32) : struct {
+ rtc_cnt_day : (14);
+ reserved(18);
+ };
+
+ skip_to(0x4B);
+ assert_pos(0x4B);
+ /** PLL configuration register */
+ reg pll_config(8) : struct {
+ pll_config_dat : (7);
+ reserved(1);
+ };
+
+ skip_to(0x4E);
+ assert_pos(0x4E);
+ /** External 32MHz clock resonance tune register */
+ reg xt32m_tune(8) : struct {
+ /** External 32MHz oscillator bias current */
+ xt32m_i_bias : enum (2) {
+ /** 75% of rated current */
+ [[ c: unqualified ]]
+ CURRENT_75 = 0,
+ /** 100% of rated current */
+ [[ c: unqualified ]]
+ CURRENT_RATED = 1,
+ /** 125% of rated current */
+ [[ c: unqualified ]]
+ CURRENT_125 = 2,
+ /** 150% of rated current */
+ [[ c: unqualified ]]
+ CURRENT_150 = 3,
+ };
+ reserved(2);
+ /** Select the built-in load capacitor that matches the external 32MHz
+ * crystal (which may affect wireless communication): Capacity =
+ * RB_XT32M_C_LOAD * 2 + 10pF, 000b-111b correspond to approximately
+ * 10pF-24pF respectively. Choose according to the parameters of crystal
+ * used; the common value is 111b. */
+ xt32m_c_load : (3);
+ reserved(1);
+ };
+ reserved(8);
+
+ assert_pos(0x50);
+ /** Oscillator frequency calibration count value register */
+ reg(16) : struct {
+ osc_cal_cnt : (14);
+ reserved(2);
+ };
+
+ assert_pos(0x52);
+ /** Oscillator frequency calibration control register */
+ reg osc_cal_ctrl(8) : struct {
+ osc_cnt_en : bit_t;
+ osc_cnt_halt : bit_t;
+ reserved(6);
+ };
+ };
+
+ instance clock_cfg at clock_base : clock_cfg_t;
+};
diff --git a/fdl/ch573/common.fdl b/fdl/ch573/common.fdl
new file mode 100644
index 0000000..779097c
--- /dev/null
+++ b/fdl/ch573/common.fdl
@@ -0,0 +1,17 @@
+package ch573.common {
+ bits bit_t : enum(1) {
+ [[ c: unqualified ]]
+ ON = 0b1,
+
+ [[ c: unqualified ]]
+ OFF = 0b0,
+ };
+
+ bits enable_t : enum(1) {
+ [[ c: unqualified ]]
+ ENABLED = 1,
+
+ [[ c: unqualified ]]
+ DISABLED = 0,
+ };
+};
diff --git a/fdl/ch573/gpio.fdl b/fdl/ch573/gpio.fdl
new file mode 100644
index 0000000..c54d956
--- /dev/null
+++ b/fdl/ch573/gpio.fdl
@@ -0,0 +1,219 @@
+import "ch573/common.fdl";
+
+/** Package for */
+package ch573.gpio {
+
+ location sys_base = 0x4000_1000;
+ location gpio_base = 0x4000_1018;
+
+ location gpio_port_a_base = 0x4000_10A0;
+ location gpio_port_b_base = 0x4000_10C0;
+
+ using ch573.common;
+
+ bits pd_drv_t : enum(1) {
+ [[ c: unqualified ]]
+ PD_DRV_DRIVE = 0,
+
+ [[ c: unqualified ]]
+ PD_DRV_OPEN_DRAIN = 1,
+ };
+
+ /** Gpio port type. */
+ type gpio_port_t : struct {
+ /** Port direction register. */
+ reg (32) : struct {
+ dir : enum(1) {
+ [[ c: unqualified ]]
+ DIR_OUT = 1,
+
+ [[ c: unqualified ]]
+ DIR_IN = 0,
+ } [16];
+ reserved(16);
+ };
+
+ /** Pin input register. */
+ reg pin(32);
+
+ /** Pin output register. */
+ reg (32) : struct {
+ out : bit_t[16];
+ reserved(16);
+ };
+
+ /** Data reset register. */
+ reg clr(32);
+
+ /** Pull-up resistor configuration. */
+ reg pu(32);
+
+ /** pull-down/drive configuration register. */
+ reg (32) : struct {
+ pd_drv : pd_drv_t[16];
+ reserved(16);
+ };
+ };
+
+ /** Gpio Type. */
+ type gpio_t : struct {
+ /** Function pin remapping register. */
+ reg pin_alternate(16) : struct {
+ /**
+ * TMR0 function pin mapping selection bit:
+ *
+ * 1: TMR0_/PWM0_/CAP0_ is mapped to PB[23]
+ * 0: TMR0_/PWM0_/CAP0_ is mapped to PA[9]
+ */
+ rw pin_tmr0 : bit_t;
+
+ /**
+ * TMR1 function pin mapping selection bit:
+ *
+ * 1: TMR1_/PWM1_/CAP1_ is mapped to PB[10];
+ * 0: TMR1/PWM1/CAP1 is mapped to PA[10].
+ */
+ rw pin_tmr1 : bit_t;
+
+ /**
+ * TMR2 function pin mapping selection bit:
+ *
+ * 1: TMR2_/PWM2_/CAP2_ is mapped to PB[11];
+ * 0: TMR2/PWM2/CAP2 is mapped to PA[11].
+ */
+ rw pin_tmr2 : bit_t;
+
+ reserved(1);
+
+ /**
+ * UART0 function pin mapping selection bit:
+ *
+ * 1: RXD0_/TXD0_ is mapped to PA[15]/PA[14];
+ * 0: RXD0/TXD0 is mapped to PB[4]/PB[7].
+ */
+ rw pin_uart0 : bit_t;
+
+ /**
+ * UART1 function pin mapping selection bit:
+ *
+ * 1: RXD1_/TXD1_ is mapped to PB[12]/PB[13];
+ * 0: RXD1/TXD1 is mapped to PA[8]/PA[9].
+ */
+ rw pin_uart1 : bit_t;
+
+ reserved(2);
+
+ /**
+ * SPI0 function pin mapping selection bit:
+ *
+ * 1: SCK0_/SCS_/MOSI_/MISO_ is mapped to PB[12]/PB[13]/PB[14]/PB[15];
+ * 0: SCK0/SCS/MOSI/MISO is mapped to PA[12]/PA[13]/PA[14]/PA[15].
+ */
+ rw pin_spi0 : bit_t;
+
+ reserved(7);
+
+ };
+
+ /** Peripheral analog pin configuration register. */
+ reg pin_analog_ie(16) : struct {
+ reserved(6);
+
+ pin_usb_dp_pu : bit_t;
+
+ /**
+ * USB pin enable:
+ *
+ * 1: PB10-11 are USB communication pins;
+ * 0: PB10-11 are not used for USB communication.
+ */
+ pin_usb_ie : bit_t;
+
+ /**
+ * ADC/TKEY 8/9 channel pin digital input disable:
+ *
+ * 1: Disable PB0/PB6 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc8_9_ie : bit_t;
+
+ /**
+ * ADC/TKEY 0 channel pin digital input disable:
+ *
+ * 1: Disable PA4 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc0_ie : bit_t;
+
+ /**
+ * ADC/TKEY 1 channel pin digital input disable:
+ *
+ * 1: Disable PA5 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc1_ie : bit_t;
+
+ /**
+ * ADC/TKEY 12 channel pin digital input disable:
+ *
+ * 1: Disable the PA8 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc12_ie : bit_t;
+
+ /**
+ * ADC/TKEY 13 channel pin digital input disable:
+ *
+ * 1: Disable PA9 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc13_ie : bit_t;
+
+ /**
+ * 32KHz crystal LSE pin digital input disable:
+ *
+ * 1: Disable PA10-11 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_xt32k_ie : bit_t;
+
+ /**
+ * ADC/TKEY 2/3 channel pin digital input disable:
+ *
+ * 1: Disable PA12-13 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc2_3_ie : bit_t;
+
+ /**
+ * ADC/TKEY 4/5 channel pin digital input disable:
+ *
+ * 1: Disable PA14-15 digital input to save power consumption;
+ * 0: Enable digital input.
+ */
+ pin_adc4_5_ie : bit_t;
+ };
+
+ /** Port A interrupt enable register. */
+ reg pa_interrupt_enable(16);
+
+ /** Port B interrupt enable register. */
+ reg pb_interrupt_enable(16);
+
+ /** Port A interrupt mode configure register. */
+ reg pa_interrupt_mode(16);
+
+ /** Port B interrupt mode configure register. */
+ reg pb_interrupt_mode(16);
+
+ /** Port A interrupt flag register. */
+ reg pa_interrupt_flag(16);
+
+ /** Port B interrupt flag register. */
+ reg pb_interrupt_flag(16);
+ };
+
+ instance gpio at gpio_base : gpio_t;
+ instance gpio_port_a at gpio_port_a_base : gpio_port_t;
+ instance gpio_port_b at gpio_port_b_base : gpio_port_t;
+};
diff --git a/fdl/ch573/spi.fdl b/fdl/ch573/spi.fdl
new file mode 100644
index 0000000..855d17f
--- /dev/null
+++ b/fdl/ch573/spi.fdl
@@ -0,0 +1,158 @@
+import "ch573/common.fdl";
+
+/** Package for the SPI subsystem. */
+package ch573.spi {
+
+ location spi_base = 0x4000_4000;
+
+ using ch573.common;
+
+ type spi_t : struct {
+ /** SPI0 Control Mode Register */
+ reg ctrl_mod(8) : struct {
+ /** SPI master/slave mode select */
+ mode_slave : bit_t;
+ /** Clear FIFO/counter/interrupt flag */
+ all_clear : bit_t;
+ /** 2-wire/3-wire SPI mode select in slave mode */
+ wire_2_mod : bit_t;
+ union {
+ /** Clock idle mode select in master mode */
+ mst_sck_mod : bit_t;
+ /** First byte command mode select in slave mode */
+ slv_cmd_mod : bit_t;
+ };
+ /** FIFO direction setting bit */
+ fifo_dir : bit_t;
+ /** SCK output enable bit */
+ sck_oe : bit_t;
+ /** MOSI output enable bit */
+ mosi_oe : bit_t;
+ /** MISO output enable bit */
+ miso_oe : bit_t;
+ };
+
+ /** SPI0 Control Configuration Register */
+ reg ctrl_cfg(8) : struct {
+ /** DMA function enable bit */
+ dma_enable : bit_t;
+ reserved(1);
+ /** DMA address loop enable bit */
+ dma_loop : bit_t;
+ reserved(1);
+ /** Auto-clear RB_SPI_IF_BYTE_END when accessing BUFFER/FIFO */
+ auto_if : bit_t;
+ /** SPI data bit sequence selection */
+ bit_order : bit_t;
+ /** Input delay enable in master mode */
+ mst_dly_en : bit_t;
+ reserved(1);
+ };
+
+ /** SPI0 Interrupt Enable Register */
+ reg inter_en(8) : struct {
+ /** All byte transmission completion interrupt enable bit */
+ ie_cnt_end : bit_t;
+ /** Single byte transmission completion interrupt enable bit */
+ ie_byte_end : bit_t;
+ /** More than half FIFO used interrupt enable bit */
+ ie_fifo_hf : bit_t;
+ /** DMA end interrupt enable bit */
+ ie_dma_end : bit_t;
+ /** FIFO overflow interrupt enable bit */
+ ie_fifo_ov : bit_t;
+ reserved(2);
+ /** Enable receiving the first byte interrupt in slave mode */
+ ie_fst_byte : bit_t;
+ };
+
+ assert_pos(0x03);
+ union {
+ /** SPI0 Clock Divider Register */
+ reg clock_div(8);
+ /** SPI0 Preset data register in slave mode. */
+ reg slave_pre(8);
+ };
+
+ assert_pos(0x04);
+ /** SPI0 Data Buffer Register */
+ reg data_buf(8);
+
+ assert_pos(0x05);
+ /** SPI0 Status Register */
+ reg status(8) : struct {
+ reserved(4);
+ /** Command receive completion in slave mode */
+ slv_cmd_act : bit_t;
+ /** FIFO ready status */
+ fifo_ready : bit_t;
+ /** First loading status after chip select in slave mode */
+ slv_cs_load : bit_t;
+ /** Chip select status in slave mode */
+ slv_select : bit_t;
+ };
+
+ assert_pos(0x06);
+ /** SPI0 Interrupt Flag Register */
+ reg int_flag(8) : struct {
+ /** All byte transmission completion flag */
+ if_cnt_end : bit_t;
+ /** Single byte transmission completion flag */
+ if_byte_end : bit_t;
+ /** More than half FIFO used flag */
+ if_fifo_hf : bit_t;
+ /** DMA completion flag */
+ if_dma_end : bit_t;
+ /** FIFO overflow flag */
+ if_fifo_ov : bit_t;
+ reserved(1);
+ /** SPI idle status */
+ free : bit_t;
+ /** First byte received flag in slave mode */
+ if_fst_byte : bit_t;
+ };
+
+ assert_pos(0x07);
+ /** SPI0 FIFO Count Register */
+ reg fifo_count(8);
+
+ skip_to(0x0C);
+ /** SPI0 Total Transmission Length Register */
+ reg total_count(16);
+
+ skip_to(0x10);
+ reg fifo(8);
+ reserved(16);
+
+ assert_pos(0x13);
+ reg fifo_count_1(8);
+
+ assert_pos(0x14);
+ /** SPI0 DMA Buffer Current Address */
+ reg (16) : struct {
+ /** DMA buffer current address (lower 14 bits valid) */
+ dma_now : (14);
+ reserved(2);
+ };
+ reserved(16);
+
+ assert_pos(0x18);
+ /** SPI0 DMA Buffer Start Address */
+ reg (16) : struct {
+ /** DMA buffer start address (lower 14 bits valid) */
+ dma_beg : (14);
+ reserved(2);
+ };
+ reserved(16);
+
+ assert_pos(0x1C);
+ /** SPI0 DMA Buffer End Address */
+ reg (16) : struct {
+ /** DMA buffer end address (lower 14 bits valid) */
+ dma_end : (14);
+ reserved(2);
+ };
+ };
+
+ instance spi0 at spi_base : spi_t;
+};
diff --git a/fdl/ch573/uart.fdl b/fdl/ch573/uart.fdl
new file mode 100644
index 0000000..bc2df2d
--- /dev/null
+++ b/fdl/ch573/uart.fdl
@@ -0,0 +1,157 @@
+import "ch573/common.fdl";
+
+/** Package for the UART subsystem. */
+package ch573.uart {
+
+ location uart0_base = 0x4000_3000;
+ location uart1_base = 0x4000_3400;
+ location uart2_base = 0x4000_3800;
+ location uart3_base = 0x4000_3C00;
+
+ using ch573.common;
+
+ type uart_t : struct {
+ /** MODEM Control Register */
+ reg mcr(8) : struct {
+ /** DTR signal output level control (UART0 only) */
+ dtr : bit_t;
+ /** RTS signal output level control (UART0 only) */
+ rts : bit_t;
+ /** User-defined MODEM control bit (UART0 only) */
+ out1 : bit_t;
+ union {
+ /** UART interrupt request output control */
+ out2 : bit_t;
+ int_oe : bit_t;
+ };
+ /** Internal loop-back test mode (UART0 only) */
+ loop : bit_t;
+ /** Automatic CTS and RTS hardware flow control (UART0 only) */
+ au_flow : bit_t;
+ /** DTR pin output is in transmission (UART0 only) */
+ tnow : bit_t;
+ /** Half-duplex mode control (UART0 only) */
+ half : bit_t;
+ };
+
+ /** Interrupt Enable Register */
+ reg ier(8) : struct {
+ /** Receive data interrupt enable */
+ recv_rdy : bit_t;
+ /** Transmit hold register empty interrupt enable */
+ thr_empty : bit_t;
+ /** Receive line status interrupt enable */
+ line_stat : bit_t;
+ /** Modem status change interrupt enable (UART0 only) */
+ modem_chg : bit_t;
+ /** DTR output enable (UART0 only) */
+ dtr_en : bit_t;
+ /** RTS output enable (UART0 only) */
+ rts_en : bit_t;
+ /** TXD output enable */
+ txd_en : bit_t;
+ /** Software reset control */
+ reset : bit_t;
+ };
+
+ /** FIFO Control Register */
+ reg fcr(8) : struct {
+ /** FIFO enable */
+ fifo_en : bit_t;
+ /** Clear receiver FIFO */
+ rx_fifo_clr : bit_t;
+ /** Clear transmitter FIFO */
+ tx_fifo_clr : bit_t;
+ reserved(3);
+ /** FIFO trigger level select */
+ fifo_trig : (2);
+ };
+
+ /** Line Control Register */
+ reg lcr(8) : struct {
+ /** UART word size (5-8 bits) */
+ word_sz : (2);
+ /** Stop bit setting */
+ stop_bit : bit_t;
+ /** Parity bit enable */
+ par_en : bit_t;
+ /** Parity bit format */
+ par_mod : (2);
+ /** Generate break line interval */
+ break_en : bit_t;
+ /** Divisor latch access enable */
+ dlab : bit_t;
+ };
+
+ /** Interrupt Identification Register */
+ reg iir(8) : struct {
+ union {
+ /** No interrupt status */
+ struct {
+ no_int : bit_t;
+ reserved(3);
+ };
+ /** Interrupt flag mask */
+ int_mask : (4);
+ };
+ reserved(2);
+ /** FIFO enable status */
+ fifo_id : (2);
+ };
+
+ /** Line Status Register */
+ reg lsr(8) : struct {
+ /** Data ready */
+ data_rdy : bit_t;
+ /** Overrun error */
+ over_err : bit_t;
+ /** Parity error */
+ par_err : bit_t;
+ /** Framing error */
+ frame_err : bit_t;
+ /** Break interrupt */
+ break_int : bit_t;
+ /** Transmitter holding register empty */
+ thr_empty : bit_t;
+ /** Transmitter empty */
+ tx_empty : bit_t;
+ /** FIFO data error */
+ fifo_err : bit_t;
+ };
+
+ skip_to(0x08);
+ union {
+ /** Transmit Hold Register. */
+ reg thr(8);
+ /** Receive Buffer Register. */
+ reg rbr(8);
+ };
+ reserved(8);
+
+ assert_pos(0x0A);
+ /** Receive FIFO Count Register */
+ reg rfc(8);
+
+ assert_pos(0x0B);
+ /** Transmit FIFO Count Register */
+ reg tfc(8);
+
+ assert_pos(0x0C);
+ /** Baud Rate Divisor Latch */
+ reg dl(16);
+
+ assert_pos(0x0E);
+ /** Prescaler Divisor Register */
+ reg div(8);
+
+ assert_pos(0x0F);
+ /** Slave Address Register (UART0 only) */
+ reg adr(8);
+ };
+
+ instance uart0 at uart0_base : uart_t;
+ instance uart1 at uart1_base : uart_t;
+ instance uart2 at uart2_base : uart_t;
+ instance uart3 at uart3_base : uart_t;
+};
+
diff --git a/include/isr_vector.h b/include/isr_vector.h
new file mode 100644
index 0000000..d916db0
--- /dev/null
+++ b/include/isr_vector.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <stdint.h>
+
+/* Type def to a void function to make things mor ereadable. */
+typedef void (*isr_routine)(void);
+
+typedef struct {
+ // What NULL points to. nothing useful.
+ uint32_t reserved__;
+ // Called when the device boots or reset is pressed.
+ isr_routine reset_cb;
+ isr_routine nmi_cb;
+ isr_routine exc_cb;
+
+ uint32_t _reserved_1[8];
+
+ isr_routine systick_cb;
+
+ uint32_t _reserved_2;
+
+ isr_routine swi_cb;
+
+ uint32_t _reserved_3;
+
+ isr_routine tmr0_cb;
+ isr_routine gpio_a_cb;
+ isr_routine gpio_b_cb;
+ isr_routine spi0_cb;
+ isr_routine blel_cb;
+ isr_routine bleb_cb;
+ isr_routine usb_cb;
+
+ uint32_t _reserved_4;
+
+ isr_routine tmr1_cb;
+ isr_routine tmr2_cb;
+ isr_routine uart0_cb;
+ isr_routine uart1_cb;
+ isr_routine rtc_cb;
+ isr_routine adc_cb;
+
+ uint32_t _reserved_5;
+
+ isr_routine pwmx_cb;
+ isr_routine tmr3_cb;
+ isr_routine uart2_cb;
+ isr_routine uart3_cb;
+ isr_routine wdog_bat_cb;
+} isr_vector_t;
+
+/** Reference to the global ISR vector. */
+extern isr_vector_t isr_vector;
+
+/** Default IRQ handler. This is weakly defined and can be overridden. */
+void default_irq_handler(void);
+
+/** Weakly defined interrput service routine vectors. These just alias to
+ * default_irq_handler if not overridden. */
+void irq_on_nmi(void);
+void irq_on_exc(void);
+void irq_on_systick(void);
+void irq_on_swi(void);
+void irq_on_tmr0(void);
+void irq_on_gpio_a(void);
+void irq_on_gpio_b(void);
+void irq_on_spi0(void);
+void irq_on_blel(void);
+void irq_on_bleb(void);
+void irq_on_usb(void);
+void irq_on_tmr1(void);
+void irq_on_tmr2(void);
+void irq_on_uart0(void);
+void irq_on_uart1(void);
+void irq_on_rtc(void);
+void irq_on_adc(void);
+void irq_on_pwmx(void);
+void irq_on_tmr3(void);
+void irq_on_uart2(void);
+void irq_on_uart3(void);
+void irq_on_wdog_bat(void);
diff --git a/linker/ls.ld b/linker/ls.ld
index dbac92b..e4cc0af 100644
--- a/linker/ls.ld
+++ b/linker/ls.ld
@@ -6,13 +6,30 @@ MEMORY
SECTIONS
{
- gpio_a = ABSOLUTE(0x400010A0);
- gpio_b = ABSOLUTE(0x400010C0);
-
. = ORIGIN(flash);
.text : ALIGN(0x04) {
*(.isr_vector);
. = ALIGN(0x100);
*(.text);
} >flash AT>flash
+
+ DATA_VALUES_IN_FLASH = LOADADDR(.data);
+
+ .data : ALIGN(0x04) {
+ . = ALIGN(0x04);
+ DATA_SEGMENT_START = .;
+ *(.data);
+ *(.data.*);
+ *(.rodata.*);
+ DATA_SEGMENT_STOP = .;
+ . = ALIGN(0x04);
+ } >sram AT>flash
+
+ .bss : ALIGN(0x04) {
+ . = ALIGN(0x04);
+ BSS_START = .;
+ *(.bss);
+ BSS_STOP = .;
+ HEAP_START = .;
+ } >sram
}
diff --git a/src/blinky.c b/src/blinky.c
index 7e46389..d8a29bd 100644
--- a/src/blinky.c
+++ b/src/blinky.c
@@ -1,5 +1,12 @@
#include <stdint.h>
+#include "ch573/gpio.h"
+
+#define GPIO_PORT_A ch573_gpio__gpio_port_a
+#define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF
+
+static void start(void);
+
/*
* Function (or really pointer to code) for the reset interrupt handler.
*/
@@ -13,62 +20,15 @@ void delay(void);
/* Type def to a void function to make things mor ereadable. */
typedef void (*isr_routine)(void);
-/* Gpio configuration structure. This is exactly how it is laid out in
- * memory. In these registers bit X referes to pin X. */
-typedef struct {
- /* The direction of the gpio pin. 1 = output, 0 = input. */
- uint32_t dir;
-
- /* The value of the gpio pin (for input). */
- uint32_t in;
-
- /* Write to set the output value for the pin. */
- uint32_t out;
-
- /* The clear value. Resets the pin to what it is at reset. */
- uint32_t clr;
-
- /* Sets the pin to be pull-up on logical 1 in input mode. */
- uint32_t pu;
-
- /* Sets whether the pin should be pull-down (open-drain) for logical 0 or
- * drive for logical 1. 1 = pull-down, 0 = drive. */
- uint32_t pd_drv;
-} gpio_t;
-
/** The ISR Vector structure. This is linked to starting at address 0. */
-__attribute((__section__(".isr_vector"))) volatile struct {
- // What NULL points to. nothing useful.
- uint32_t reserved__;
- // Called when the device boots or reset is pressed.
- isr_routine reset_cb;
- isr_routine nmi_cb;
- isr_routine exc_cb;
-} isr_vectors = {.reset_cb = on_reset};
-
-// GPIO configuration registers. These are defined in the linker script.
-extern volatile gpio_t gpio_a;
-extern volatile gpio_t gpio_b;
-
-/* Main routine. This is called on_reset once everything else has been set up.
- */
-static void start(void)
-{
- uint32_t bit = 1 << 8;
- gpio_a.dir |= bit; // Set to "out"
- gpio_a.pd_drv |= bit; // Set to "open drain"
-
- for (;;) {
- gpio_a.out &= ~bit; // Pin low (turns on LED)
- delay();
- delay();
- delay();
- gpio_a.out |= bit; // Pin high (turns off LED)
- delay();
- delay();
- delay();
- }
-}
+// __attribute((__section__(".isr_vector"))) volatile struct {
+// // What NULL points to. nothing useful.
+// uint32_t reserved__;
+// // Called when the device boots or reset is pressed.
+// isr_routine reset_cb;
+// isr_routine nmi_cb;
+// isr_routine exc_cb;
+// } isr_vectors = {.reset_cb = on_reset};
/*
* The reset callback.This has to be a naked function because the stack pointer
@@ -87,8 +47,68 @@ __attribute((naked)) void on_reset(void)
: "r"(start));
}
+uint32_t collatz(uint32_t n)
+{
+ uint32_t c = 0;
+
+ while (n > 1) {
+ if (n % 2 == 0) {
+ n /= 2;
+ } else {
+ n = n * 3 + 1;
+ }
+ c++;
+ }
+
+ return c;
+}
+
+void blink_n(int n)
+{
+ uint32_t bit = 1 << 8;
+ while (n > 0) {
+ GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8);
+ delay();
+ GPIO_PORT.out.set(GPIO_PORT_A, ON, 8);
+ delay();
+ --n;
+ }
+}
+
void delay(void)
{
- for (volatile uint32_t i = 0; i < 10000; ++i)
- ;
+ for (volatile uint32_t i = 0; i < 10000; ++i);
+}
+
+/* Main routine. This is called on_reset once everything else has been set up.
+ */
+static void start(void)
+{
+ GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, 8);
+ GPIO_PORT.pd_drv.set(GPIO_PORT_A, PD_DRV_OPEN_DRAIN, 8);
+
+ for (;;) {
+ GPIO_PORT.out.set(GPIO_PORT_A, ON, 8);
+ delay();
+ delay();
+ delay();
+ GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8);
+ delay();
+ }
+
+ // uint32_t i;
+ // for (i = 1;; ++i) {
+ // uint32_t c = collatz(i);
+ // blink_n(c);
+
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // delay();
+ // }
}
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..8d895f5
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,143 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include "isr_vector.h"
+#include "ch573/gpio.h"
+
+_Static_assert(offsetof(typeof(isr_vector_t), nmi_cb) == 0x8, "Offset wrong");
+
+_Static_assert(
+ offsetof(typeof(isr_vector_t), systick_cb) == 0x30, "Offset wrong ");
+
+_Static_assert(
+ offsetof(typeof(isr_vector_t), tmr0_cb) == 0x40, "Offset wrong ");
+
+_Static_assert(
+ offsetof(typeof(isr_vector_t), tmr1_cb) == 0x60, "Offset wrong ");
+
+_Static_assert(
+ offsetof(typeof(isr_vector_t), pwmx_cb) == 0x7c, "Offset wrong ");
+
+_Static_assert(
+ offsetof(typeof(isr_vector_t), wdog_bat_cb) == 0x8c, "Offset wrong ");
+
+void on_reset(void);
+
+void __attribute__((weak, interrupt)) default_irq_handler(void)
+{
+ return;
+}
+
+#define WEAK_IRQ(irq) \
+ void __attribute__((weak, alias("default_irq_handler"))) irq(void)
+
+WEAK_IRQ(irq_on_nmi);
+WEAK_IRQ(irq_on_exc);
+WEAK_IRQ(irq_on_systick);
+WEAK_IRQ(irq_on_swi);
+WEAK_IRQ(irq_on_tmr0);
+WEAK_IRQ(irq_on_gpio_a);
+WEAK_IRQ(irq_on_gpio_b);
+WEAK_IRQ(irq_on_spi0);
+WEAK_IRQ(irq_on_blel);
+WEAK_IRQ(irq_on_bleb);
+WEAK_IRQ(irq_on_usb);
+WEAK_IRQ(irq_on_tmr1);
+WEAK_IRQ(irq_on_tmr2);
+WEAK_IRQ(irq_on_uart0);
+WEAK_IRQ(irq_on_uart1);
+WEAK_IRQ(irq_on_rtc);
+WEAK_IRQ(irq_on_adc);
+WEAK_IRQ(irq_on_pwmx);
+WEAK_IRQ(irq_on_tmr3);
+WEAK_IRQ(irq_on_uart2);
+WEAK_IRQ(irq_on_uart3);
+WEAK_IRQ(irq_on_wdog_bat);
+
+/** The ISR Vector structure. This is linked to starting at address 0. */
+__attribute((__section__(".isr_vector"))) volatile isr_vector_t isr_vectors = {
+ .reset_cb = on_reset,
+ .nmi_cb = irq_on_nmi,
+ .exc_cb = irq_on_exc,
+ .systick_cb = irq_on_systick,
+ .swi_cb = irq_on_swi,
+ .tmr0_cb = irq_on_tmr0,
+ .gpio_a_cb = irq_on_gpio_a,
+ .gpio_b_cb = irq_on_gpio_b,
+ .spi0_cb = irq_on_spi0,
+ .blel_cb = irq_on_blel,
+ .bleb_cb = irq_on_bleb,
+ .usb_cb = irq_on_usb,
+ .tmr1_cb = irq_on_tmr1,
+ .tmr2_cb = irq_on_tmr2,
+ .uart0_cb = irq_on_uart0,
+ .uart1_cb = irq_on_uart1,
+ .rtc_cb = irq_on_rtc,
+ .adc_cb = irq_on_adc,
+ .pwmx_cb = irq_on_pwmx,
+ .tmr3_cb = irq_on_tmr3,
+ .uart2_cb = irq_on_uart2,
+ .uart3_cb = irq_on_uart3,
+ .wdog_bat_cb = irq_on_wdog_bat,
+};
+
+// Memory-mapped address of the data values in flash.
+extern uint32_t* DATA_VALUES_IN_FLASH;
+
+// Where the data is located in sram.
+extern uint32_t* DATA_SEGMENT_START;
+extern uint32_t* DATA_SEGMENT_STOP;
+
+// Where 0-initialized data is in sram.
+extern uint32_t* BSS_START;
+extern uint32_t* BSS_STOP;
+
+/*
+ * Initialize the data segment and the bss segment.
+ *
+ * This function loads data in the .data section from flash and puts it in
+ * memory where it can be edited and initialized the BSS data to 0.
+ */
+void init_data_segments(void)
+{
+ uint32_t* src = DATA_VALUES_IN_FLASH;
+ uint32_t* dest = DATA_SEGMENT_START;
+
+ while (dest != DATA_SEGMENT_STOP) {
+ *(dest++) = *(src++);
+ }
+
+ dest = BSS_START;
+ while (dest != BSS_STOP) {
+ *(dest++) = 0;
+ }
+}
+
+/*
+ * External reference to the main() function.
+ */
+extern void main(void);
+
+#define GPIO_PORT_A ch573_gpio__gpio_port_a
+#define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF
+/* Start function. Responsible for initializing the system and jumping to the
+ * main function. */
+// static void start(void)
+// {
+// // init_data_segments();
+// GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, 8);
+// GPIO_PORT.pd_drv.set(GPIO_PORT_A, PD_DRV_OPEN_DRAIN, 8);
+// GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8);
+//
+// main();
+// }
+
+/*
+ * The reset callback.This has to be a naked function because the stack pointer
+ * may not be initialized!!.
+ */
+
+/*
+ * The reset callback.This has to be a naked function because the stack pointer
+ * may not be initialized!!.
+ */