diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-13 23:05:32 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-13 23:05:32 -0700 |
commit | c9402e5a5d67ef877fa7f5f67c07a794574ded35 (patch) | |
tree | aad50c7d861f3f4c68d985abe1b8fce79d10bc86 | |
parent | da45a7210ef634fcdb0270bffc90d4da97c61230 (diff) | |
download | ch573-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.txt | 12 | ||||
-rw-r--r-- | fdl/ch573/clock.fdl | 209 | ||||
-rw-r--r-- | fdl/ch573/common.fdl | 17 | ||||
-rw-r--r-- | fdl/ch573/gpio.fdl | 219 | ||||
-rw-r--r-- | fdl/ch573/spi.fdl | 158 | ||||
-rw-r--r-- | fdl/ch573/uart.fdl | 157 | ||||
-rw-r--r-- | include/isr_vector.h | 81 | ||||
-rw-r--r-- | linker/ls.ld | 23 | ||||
-rw-r--r-- | src/blinky.c | 134 | ||||
-rw-r--r-- | src/init.c | 143 |
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!!. + */ |