From 1dc7d758f96dd2b9bd7b03f01ca032d68b696cf0 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 2 Nov 2014 10:14:39 +0000 Subject: fish --- libopencm3/lib/Makefile.include | 52 + libopencm3/lib/cm3/assert.c | 34 + libopencm3/lib/cm3/dwt.c | 77 + libopencm3/lib/cm3/nvic.c | 199 ++ libopencm3/lib/cm3/scb.c | 47 + libopencm3/lib/cm3/sync.c | 73 + libopencm3/lib/cm3/systick.c | 203 ++ libopencm3/lib/cm3/vector.c | 121 ++ libopencm3/lib/dispatch/vector_chipset.c | 12 + libopencm3/lib/efm32/efm32g/Makefile | 43 + libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld | 106 + .../lib/efm32/efm32g/libopencm3_efm32g880f128.ld | 15 + libopencm3/lib/efm32/efm32gg/Makefile | 43 + libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld | 106 + .../efm32/efm32gg/libopencm3_efm32gg990f1024.ld | 15 + libopencm3/lib/efm32/efm32lg/Makefile | 43 + libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld | 106 + libopencm3/lib/efm32/efm32tg/Makefile | 43 + libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld | 106 + .../lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld | 15 + libopencm3/lib/ethernet/mac.c | 43 + libopencm3/lib/ethernet/mac_stm32fxx7.c | 378 ++++ libopencm3/lib/ethernet/phy.c | 64 + libopencm3/lib/ethernet/phy_ksz8051mll.c | 89 + libopencm3/lib/lm3s/Makefile | 40 + libopencm3/lib/lm3s/gpio.c | 52 + libopencm3/lib/lm3s/libopencm3_lm3s.ld | 106 + libopencm3/lib/lm4f/Makefile | 43 + libopencm3/lib/lm4f/gpio.c | 598 ++++++ libopencm3/lib/lm4f/libopencm3_lm4f.ld | 2 + libopencm3/lib/lm4f/rcc.c | 499 +++++ libopencm3/lib/lm4f/systemcontrol.c | 40 + libopencm3/lib/lm4f/uart.c | 627 ++++++ libopencm3/lib/lm4f/usb_lm4f.c | 651 ++++++ libopencm3/lib/lpc13xx/Makefile | 40 + libopencm3/lib/lpc13xx/gpio.c | 42 + libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld | 106 + libopencm3/lib/lpc17xx/Makefile | 40 + libopencm3/lib/lpc17xx/gpio.c | 48 + libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld | 106 + libopencm3/lib/lpc43xx/gpio.c | 53 + libopencm3/lib/lpc43xx/i2c.c | 102 + libopencm3/lib/lpc43xx/ipc.c | 58 + libopencm3/lib/lpc43xx/m0/Makefile | 43 + libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld | 0 .../lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld | 96 + libopencm3/lib/lpc43xx/m4/Makefile | 50 + libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld | 127 ++ .../lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld | 139 ++ .../lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld | 128 ++ libopencm3/lib/lpc43xx/m4/vector_chipset.c | 48 + libopencm3/lib/lpc43xx/scu.c | 52 + libopencm3/lib/lpc43xx/ssp.c | 140 ++ libopencm3/lib/lpc43xx/timer.c | 72 + libopencm3/lib/lpc43xx/uart.c | 243 +++ libopencm3/lib/sam/3a/Makefile | 37 + libopencm3/lib/sam/3a/libopencm3_sam3a.ld | 106 + libopencm3/lib/sam/3n/Makefile | 37 + libopencm3/lib/sam/3n/libopencm3_sam3n.ld | 106 + libopencm3/lib/sam/3s/Makefile | 38 + libopencm3/lib/sam/3s/libopencm3_sam3s.ld | 106 + libopencm3/lib/sam/3u/Makefile | 38 + libopencm3/lib/sam/3u/libopencm3_sam3u.ld | 106 + libopencm3/lib/sam/3x/Makefile | 37 + libopencm3/lib/sam/3x/libopencm3_sam3x.ld | 106 + libopencm3/lib/sam/common/gpio.c | 64 + libopencm3/lib/sam/common/pmc.c | 97 + libopencm3/lib/sam/common/usart.c | 110 + libopencm3/lib/stm32/can.c | 557 +++++ libopencm3/lib/stm32/common/adc_common_v1.c | 755 +++++++ libopencm3/lib/stm32/common/crc_common_all.c | 81 + libopencm3/lib/stm32/common/crypto_common_f24.c | 175 ++ libopencm3/lib/stm32/common/dac_common_all.c | 503 +++++ libopencm3/lib/stm32/common/dma_common_f24.c | 794 +++++++ libopencm3/lib/stm32/common/dma_common_l1f013.c | 435 ++++ libopencm3/lib/stm32/common/exti_common_all.c | 154 ++ libopencm3/lib/stm32/common/flash_common_f01.c | 235 +++ libopencm3/lib/stm32/common/flash_common_f234.c | 121 ++ libopencm3/lib/stm32/common/flash_common_f24.c | 416 ++++ libopencm3/lib/stm32/common/gpio_common_all.c | 151 ++ libopencm3/lib/stm32/common/gpio_common_f0234.c | 206 ++ libopencm3/lib/stm32/common/hash_common_f24.c | 163 ++ libopencm3/lib/stm32/common/i2c_common_all.c | 419 ++++ libopencm3/lib/stm32/common/iwdg_common_all.c | 149 ++ libopencm3/lib/stm32/common/pwr_common_all.c | 205 ++ libopencm3/lib/stm32/common/rcc_common_all.c | 188 ++ libopencm3/lib/stm32/common/rtc_common_l1f024.c | 123 ++ libopencm3/lib/stm32/common/spi_common_all.c | 710 +++++++ libopencm3/lib/stm32/common/spi_common_f03.c | 177 ++ libopencm3/lib/stm32/common/spi_common_l1f124.c | 137 ++ libopencm3/lib/stm32/common/timer_common_all.c | 2177 ++++++++++++++++++++ libopencm3/lib/stm32/common/timer_common_f234.c | 58 + libopencm3/lib/stm32/common/timer_common_f24.c | 53 + libopencm3/lib/stm32/common/usart_common_all.c | 367 ++++ libopencm3/lib/stm32/common/usart_common_f124.c | 143 ++ libopencm3/lib/stm32/desig.c | 54 + libopencm3/lib/stm32/f0/Makefile | 49 + libopencm3/lib/stm32/f0/adc.c | 835 ++++++++ libopencm3/lib/stm32/f0/comparator.c | 64 + libopencm3/lib/stm32/f0/crc.c | 31 + libopencm3/lib/stm32/f0/crs.c | 32 + libopencm3/lib/stm32/f0/dac.c | 31 + libopencm3/lib/stm32/f0/dma.c | 31 + libopencm3/lib/stm32/f0/flash.c | 157 ++ libopencm3/lib/stm32/f0/gpio.c | 31 + libopencm3/lib/stm32/f0/i2c.c | 32 + libopencm3/lib/stm32/f0/iwdg.c | 31 + libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld | 106 + libopencm3/lib/stm32/f0/pwr.c | 38 + libopencm3/lib/stm32/f0/rcc.c | 665 ++++++ libopencm3/lib/stm32/f0/rtc.c | 31 + libopencm3/lib/stm32/f0/spi.c | 31 + libopencm3/lib/stm32/f0/syscfg.c | 31 + libopencm3/lib/stm32/f0/timer.c | 34 + libopencm3/lib/stm32/f0/usart.c | 429 ++++ libopencm3/lib/stm32/f1/Makefile | 53 + libopencm3/lib/stm32/f1/adc.c | 452 ++++ libopencm3/lib/stm32/f1/crc.c | 31 + libopencm3/lib/stm32/f1/dac.c | 31 + libopencm3/lib/stm32/f1/dma.c | 31 + libopencm3/lib/stm32/f1/ethernet.c | 52 + libopencm3/lib/stm32/f1/flash.c | 306 +++ libopencm3/lib/stm32/f1/gpio.c | 194 ++ libopencm3/lib/stm32/f1/i2c.c | 31 + libopencm3/lib/stm32/f1/iwdg.c | 31 + libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld | 106 + libopencm3/lib/stm32/f1/pwr.c | 43 + libopencm3/lib/stm32/f1/rcc.c | 1106 ++++++++++ libopencm3/lib/stm32/f1/rtc.c | 305 +++ libopencm3/lib/stm32/f1/spi.c | 31 + libopencm3/lib/stm32/f1/stm32f100x4.ld | 31 + libopencm3/lib/stm32/f1/stm32f100x6.ld | 31 + libopencm3/lib/stm32/f1/stm32f100x8.ld | 31 + libopencm3/lib/stm32/f1/stm32f100xb.ld | 31 + libopencm3/lib/stm32/f1/stm32f100xc.ld | 31 + libopencm3/lib/stm32/f1/stm32f100xd.ld | 31 + libopencm3/lib/stm32/f1/stm32f100xe.ld | 31 + libopencm3/lib/stm32/f1/timer.c | 57 + libopencm3/lib/stm32/f1/usart.c | 31 + libopencm3/lib/stm32/f2/Makefile | 52 + libopencm3/lib/stm32/f2/crc.c | 33 + libopencm3/lib/stm32/f2/crypto.c | 31 + libopencm3/lib/stm32/f2/dac.c | 31 + libopencm3/lib/stm32/f2/dma.c | 31 + libopencm3/lib/stm32/f2/flash.c | 53 + libopencm3/lib/stm32/f2/gpio.c | 31 + libopencm3/lib/stm32/f2/hash.c | 31 + libopencm3/lib/stm32/f2/i2c.c | 33 + libopencm3/lib/stm32/f2/iwdg.c | 31 + libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld | 106 + libopencm3/lib/stm32/f2/pwr.c | 39 + libopencm3/lib/stm32/f2/rcc.c | 417 ++++ libopencm3/lib/stm32/f2/rtc.c | 31 + libopencm3/lib/stm32/f2/spi.c | 31 + libopencm3/lib/stm32/f2/timer.c | 38 + libopencm3/lib/stm32/f2/usart.c | 31 + libopencm3/lib/stm32/f3/Makefile | 50 + libopencm3/lib/stm32/f3/adc.c | 1150 +++++++++++ libopencm3/lib/stm32/f3/crc.c | 33 + libopencm3/lib/stm32/f3/dac.c | 31 + libopencm3/lib/stm32/f3/dma.c | 31 + libopencm3/lib/stm32/f3/flash.c | 63 + libopencm3/lib/stm32/f3/i2c.c | 486 +++++ libopencm3/lib/stm32/f3/iwdg.c | 31 + libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld | 106 + libopencm3/lib/stm32/f3/pwr.c | 40 + libopencm3/lib/stm32/f3/rcc.c | 465 +++++ libopencm3/lib/stm32/f3/rtc.c | 38 + libopencm3/lib/stm32/f3/spi.c | 31 + libopencm3/lib/stm32/f3/timer.c | 33 + libopencm3/lib/stm32/f3/usart.c | 140 ++ libopencm3/lib/stm32/f3/vector_chipset.c | 27 + libopencm3/lib/stm32/f4/Makefile | 59 + libopencm3/lib/stm32/f4/adc.c | 437 ++++ libopencm3/lib/stm32/f4/crc.c | 33 + libopencm3/lib/stm32/f4/crypto.c | 66 + libopencm3/lib/stm32/f4/dac.c | 31 + libopencm3/lib/stm32/f4/dma.c | 31 + libopencm3/lib/stm32/f4/flash.c | 53 + libopencm3/lib/stm32/f4/fmc.c | 99 + libopencm3/lib/stm32/f4/gpio.c | 31 + libopencm3/lib/stm32/f4/hash.c | 31 + libopencm3/lib/stm32/f4/i2c.c | 31 + libopencm3/lib/stm32/f4/iwdg.c | 31 + libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld | 106 + libopencm3/lib/stm32/f4/pwr.c | 46 + libopencm3/lib/stm32/f4/rcc.c | 539 +++++ libopencm3/lib/stm32/f4/rtc.c | 97 + libopencm3/lib/stm32/f4/spi.c | 31 + libopencm3/lib/stm32/f4/stm32f405x6.ld | 33 + libopencm3/lib/stm32/f4/timer.c | 38 + libopencm3/lib/stm32/f4/usart.c | 31 + libopencm3/lib/stm32/f4/vector_chipset.c | 27 + libopencm3/lib/stm32/l1/Makefile | 52 + libopencm3/lib/stm32/l1/adc.c | 201 ++ libopencm3/lib/stm32/l1/crc.c | 33 + libopencm3/lib/stm32/l1/dac.c | 31 + libopencm3/lib/stm32/l1/dma.c | 31 + libopencm3/lib/stm32/l1/flash.c | 208 ++ libopencm3/lib/stm32/l1/gpio.c | 31 + libopencm3/lib/stm32/l1/i2c.c | 31 + libopencm3/lib/stm32/l1/iwdg.c | 31 + libopencm3/lib/stm32/l1/lcd.c | 154 ++ libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld | 106 + libopencm3/lib/stm32/l1/pwr.c | 58 + libopencm3/lib/stm32/l1/rcc.c | 534 +++++ libopencm3/lib/stm32/l1/rtc.c | 31 + libopencm3/lib/stm32/l1/spi.c | 31 + libopencm3/lib/stm32/l1/stm32l15xx6.ld | 32 + libopencm3/lib/stm32/l1/stm32l15xx8.ld | 32 + libopencm3/lib/stm32/l1/stm32l15xxb.ld | 32 + libopencm3/lib/stm32/l1/stm32l15xxc.ld | 32 + libopencm3/lib/stm32/l1/stm32l15xxd.ld | 32 + libopencm3/lib/stm32/l1/timer.c | 59 + libopencm3/lib/stm32/l1/usart.c | 31 + libopencm3/lib/usb/usb.c | 175 ++ libopencm3/lib/usb/usb_control.c | 288 +++ libopencm3/lib/usb/usb_f103.c | 346 ++++ libopencm3/lib/usb/usb_f107.c | 91 + libopencm3/lib/usb/usb_f207.c | 91 + libopencm3/lib/usb/usb_fx07_common.c | 338 +++ libopencm3/lib/usb/usb_fx07_common.h | 39 + libopencm3/lib/usb/usb_msc.c | 814 ++++++++ libopencm3/lib/usb/usb_private.h | 163 ++ libopencm3/lib/usb/usb_standard.c | 532 +++++ 225 files changed, 33291 insertions(+) create mode 100644 libopencm3/lib/Makefile.include create mode 100644 libopencm3/lib/cm3/assert.c create mode 100644 libopencm3/lib/cm3/dwt.c create mode 100644 libopencm3/lib/cm3/nvic.c create mode 100644 libopencm3/lib/cm3/scb.c create mode 100644 libopencm3/lib/cm3/sync.c create mode 100644 libopencm3/lib/cm3/systick.c create mode 100644 libopencm3/lib/cm3/vector.c create mode 100644 libopencm3/lib/dispatch/vector_chipset.c create mode 100644 libopencm3/lib/efm32/efm32g/Makefile create mode 100644 libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld create mode 100644 libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld create mode 100644 libopencm3/lib/efm32/efm32gg/Makefile create mode 100644 libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld create mode 100644 libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld create mode 100644 libopencm3/lib/efm32/efm32lg/Makefile create mode 100644 libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld create mode 100644 libopencm3/lib/efm32/efm32tg/Makefile create mode 100644 libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld create mode 100644 libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld create mode 100644 libopencm3/lib/ethernet/mac.c create mode 100644 libopencm3/lib/ethernet/mac_stm32fxx7.c create mode 100644 libopencm3/lib/ethernet/phy.c create mode 100644 libopencm3/lib/ethernet/phy_ksz8051mll.c create mode 100644 libopencm3/lib/lm3s/Makefile create mode 100644 libopencm3/lib/lm3s/gpio.c create mode 100644 libopencm3/lib/lm3s/libopencm3_lm3s.ld create mode 100644 libopencm3/lib/lm4f/Makefile create mode 100644 libopencm3/lib/lm4f/gpio.c create mode 100644 libopencm3/lib/lm4f/libopencm3_lm4f.ld create mode 100644 libopencm3/lib/lm4f/rcc.c create mode 100644 libopencm3/lib/lm4f/systemcontrol.c create mode 100644 libopencm3/lib/lm4f/uart.c create mode 100644 libopencm3/lib/lm4f/usb_lm4f.c create mode 100644 libopencm3/lib/lpc13xx/Makefile create mode 100644 libopencm3/lib/lpc13xx/gpio.c create mode 100644 libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld create mode 100644 libopencm3/lib/lpc17xx/Makefile create mode 100644 libopencm3/lib/lpc17xx/gpio.c create mode 100644 libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld create mode 100644 libopencm3/lib/lpc43xx/gpio.c create mode 100644 libopencm3/lib/lpc43xx/i2c.c create mode 100644 libopencm3/lib/lpc43xx/ipc.c create mode 100644 libopencm3/lib/lpc43xx/m0/Makefile create mode 100644 libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld create mode 100644 libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld create mode 100644 libopencm3/lib/lpc43xx/m4/Makefile create mode 100644 libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld create mode 100644 libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld create mode 100644 libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld create mode 100644 libopencm3/lib/lpc43xx/m4/vector_chipset.c create mode 100644 libopencm3/lib/lpc43xx/scu.c create mode 100644 libopencm3/lib/lpc43xx/ssp.c create mode 100644 libopencm3/lib/lpc43xx/timer.c create mode 100644 libopencm3/lib/lpc43xx/uart.c create mode 100644 libopencm3/lib/sam/3a/Makefile create mode 100644 libopencm3/lib/sam/3a/libopencm3_sam3a.ld create mode 100644 libopencm3/lib/sam/3n/Makefile create mode 100644 libopencm3/lib/sam/3n/libopencm3_sam3n.ld create mode 100644 libopencm3/lib/sam/3s/Makefile create mode 100644 libopencm3/lib/sam/3s/libopencm3_sam3s.ld create mode 100644 libopencm3/lib/sam/3u/Makefile create mode 100644 libopencm3/lib/sam/3u/libopencm3_sam3u.ld create mode 100644 libopencm3/lib/sam/3x/Makefile create mode 100644 libopencm3/lib/sam/3x/libopencm3_sam3x.ld create mode 100644 libopencm3/lib/sam/common/gpio.c create mode 100644 libopencm3/lib/sam/common/pmc.c create mode 100644 libopencm3/lib/sam/common/usart.c create mode 100644 libopencm3/lib/stm32/can.c create mode 100644 libopencm3/lib/stm32/common/adc_common_v1.c create mode 100644 libopencm3/lib/stm32/common/crc_common_all.c create mode 100644 libopencm3/lib/stm32/common/crypto_common_f24.c create mode 100644 libopencm3/lib/stm32/common/dac_common_all.c create mode 100644 libopencm3/lib/stm32/common/dma_common_f24.c create mode 100644 libopencm3/lib/stm32/common/dma_common_l1f013.c create mode 100644 libopencm3/lib/stm32/common/exti_common_all.c create mode 100644 libopencm3/lib/stm32/common/flash_common_f01.c create mode 100644 libopencm3/lib/stm32/common/flash_common_f234.c create mode 100644 libopencm3/lib/stm32/common/flash_common_f24.c create mode 100644 libopencm3/lib/stm32/common/gpio_common_all.c create mode 100644 libopencm3/lib/stm32/common/gpio_common_f0234.c create mode 100644 libopencm3/lib/stm32/common/hash_common_f24.c create mode 100644 libopencm3/lib/stm32/common/i2c_common_all.c create mode 100644 libopencm3/lib/stm32/common/iwdg_common_all.c create mode 100644 libopencm3/lib/stm32/common/pwr_common_all.c create mode 100644 libopencm3/lib/stm32/common/rcc_common_all.c create mode 100644 libopencm3/lib/stm32/common/rtc_common_l1f024.c create mode 100644 libopencm3/lib/stm32/common/spi_common_all.c create mode 100644 libopencm3/lib/stm32/common/spi_common_f03.c create mode 100644 libopencm3/lib/stm32/common/spi_common_l1f124.c create mode 100644 libopencm3/lib/stm32/common/timer_common_all.c create mode 100644 libopencm3/lib/stm32/common/timer_common_f234.c create mode 100644 libopencm3/lib/stm32/common/timer_common_f24.c create mode 100644 libopencm3/lib/stm32/common/usart_common_all.c create mode 100644 libopencm3/lib/stm32/common/usart_common_f124.c create mode 100644 libopencm3/lib/stm32/desig.c create mode 100644 libopencm3/lib/stm32/f0/Makefile create mode 100644 libopencm3/lib/stm32/f0/adc.c create mode 100644 libopencm3/lib/stm32/f0/comparator.c create mode 100644 libopencm3/lib/stm32/f0/crc.c create mode 100644 libopencm3/lib/stm32/f0/crs.c create mode 100644 libopencm3/lib/stm32/f0/dac.c create mode 100644 libopencm3/lib/stm32/f0/dma.c create mode 100644 libopencm3/lib/stm32/f0/flash.c create mode 100644 libopencm3/lib/stm32/f0/gpio.c create mode 100644 libopencm3/lib/stm32/f0/i2c.c create mode 100644 libopencm3/lib/stm32/f0/iwdg.c create mode 100644 libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld create mode 100644 libopencm3/lib/stm32/f0/pwr.c create mode 100644 libopencm3/lib/stm32/f0/rcc.c create mode 100644 libopencm3/lib/stm32/f0/rtc.c create mode 100644 libopencm3/lib/stm32/f0/spi.c create mode 100644 libopencm3/lib/stm32/f0/syscfg.c create mode 100644 libopencm3/lib/stm32/f0/timer.c create mode 100644 libopencm3/lib/stm32/f0/usart.c create mode 100644 libopencm3/lib/stm32/f1/Makefile create mode 100644 libopencm3/lib/stm32/f1/adc.c create mode 100644 libopencm3/lib/stm32/f1/crc.c create mode 100644 libopencm3/lib/stm32/f1/dac.c create mode 100644 libopencm3/lib/stm32/f1/dma.c create mode 100644 libopencm3/lib/stm32/f1/ethernet.c create mode 100644 libopencm3/lib/stm32/f1/flash.c create mode 100644 libopencm3/lib/stm32/f1/gpio.c create mode 100644 libopencm3/lib/stm32/f1/i2c.c create mode 100644 libopencm3/lib/stm32/f1/iwdg.c create mode 100644 libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld create mode 100644 libopencm3/lib/stm32/f1/pwr.c create mode 100644 libopencm3/lib/stm32/f1/rcc.c create mode 100644 libopencm3/lib/stm32/f1/rtc.c create mode 100644 libopencm3/lib/stm32/f1/spi.c create mode 100644 libopencm3/lib/stm32/f1/stm32f100x4.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100x6.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100x8.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100xb.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100xc.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100xd.ld create mode 100644 libopencm3/lib/stm32/f1/stm32f100xe.ld create mode 100644 libopencm3/lib/stm32/f1/timer.c create mode 100644 libopencm3/lib/stm32/f1/usart.c create mode 100644 libopencm3/lib/stm32/f2/Makefile create mode 100644 libopencm3/lib/stm32/f2/crc.c create mode 100644 libopencm3/lib/stm32/f2/crypto.c create mode 100644 libopencm3/lib/stm32/f2/dac.c create mode 100644 libopencm3/lib/stm32/f2/dma.c create mode 100644 libopencm3/lib/stm32/f2/flash.c create mode 100644 libopencm3/lib/stm32/f2/gpio.c create mode 100644 libopencm3/lib/stm32/f2/hash.c create mode 100644 libopencm3/lib/stm32/f2/i2c.c create mode 100644 libopencm3/lib/stm32/f2/iwdg.c create mode 100644 libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld create mode 100644 libopencm3/lib/stm32/f2/pwr.c create mode 100644 libopencm3/lib/stm32/f2/rcc.c create mode 100644 libopencm3/lib/stm32/f2/rtc.c create mode 100644 libopencm3/lib/stm32/f2/spi.c create mode 100644 libopencm3/lib/stm32/f2/timer.c create mode 100644 libopencm3/lib/stm32/f2/usart.c create mode 100644 libopencm3/lib/stm32/f3/Makefile create mode 100644 libopencm3/lib/stm32/f3/adc.c create mode 100644 libopencm3/lib/stm32/f3/crc.c create mode 100644 libopencm3/lib/stm32/f3/dac.c create mode 100644 libopencm3/lib/stm32/f3/dma.c create mode 100644 libopencm3/lib/stm32/f3/flash.c create mode 100644 libopencm3/lib/stm32/f3/i2c.c create mode 100644 libopencm3/lib/stm32/f3/iwdg.c create mode 100644 libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld create mode 100644 libopencm3/lib/stm32/f3/pwr.c create mode 100644 libopencm3/lib/stm32/f3/rcc.c create mode 100644 libopencm3/lib/stm32/f3/rtc.c create mode 100644 libopencm3/lib/stm32/f3/spi.c create mode 100644 libopencm3/lib/stm32/f3/timer.c create mode 100644 libopencm3/lib/stm32/f3/usart.c create mode 100644 libopencm3/lib/stm32/f3/vector_chipset.c create mode 100644 libopencm3/lib/stm32/f4/Makefile create mode 100644 libopencm3/lib/stm32/f4/adc.c create mode 100644 libopencm3/lib/stm32/f4/crc.c create mode 100644 libopencm3/lib/stm32/f4/crypto.c create mode 100644 libopencm3/lib/stm32/f4/dac.c create mode 100644 libopencm3/lib/stm32/f4/dma.c create mode 100644 libopencm3/lib/stm32/f4/flash.c create mode 100644 libopencm3/lib/stm32/f4/fmc.c create mode 100644 libopencm3/lib/stm32/f4/gpio.c create mode 100644 libopencm3/lib/stm32/f4/hash.c create mode 100644 libopencm3/lib/stm32/f4/i2c.c create mode 100644 libopencm3/lib/stm32/f4/iwdg.c create mode 100644 libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld create mode 100644 libopencm3/lib/stm32/f4/pwr.c create mode 100644 libopencm3/lib/stm32/f4/rcc.c create mode 100644 libopencm3/lib/stm32/f4/rtc.c create mode 100644 libopencm3/lib/stm32/f4/spi.c create mode 100644 libopencm3/lib/stm32/f4/stm32f405x6.ld create mode 100644 libopencm3/lib/stm32/f4/timer.c create mode 100644 libopencm3/lib/stm32/f4/usart.c create mode 100644 libopencm3/lib/stm32/f4/vector_chipset.c create mode 100644 libopencm3/lib/stm32/l1/Makefile create mode 100644 libopencm3/lib/stm32/l1/adc.c create mode 100644 libopencm3/lib/stm32/l1/crc.c create mode 100644 libopencm3/lib/stm32/l1/dac.c create mode 100644 libopencm3/lib/stm32/l1/dma.c create mode 100644 libopencm3/lib/stm32/l1/flash.c create mode 100644 libopencm3/lib/stm32/l1/gpio.c create mode 100644 libopencm3/lib/stm32/l1/i2c.c create mode 100644 libopencm3/lib/stm32/l1/iwdg.c create mode 100644 libopencm3/lib/stm32/l1/lcd.c create mode 100644 libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld create mode 100644 libopencm3/lib/stm32/l1/pwr.c create mode 100644 libopencm3/lib/stm32/l1/rcc.c create mode 100644 libopencm3/lib/stm32/l1/rtc.c create mode 100644 libopencm3/lib/stm32/l1/spi.c create mode 100644 libopencm3/lib/stm32/l1/stm32l15xx6.ld create mode 100644 libopencm3/lib/stm32/l1/stm32l15xx8.ld create mode 100644 libopencm3/lib/stm32/l1/stm32l15xxb.ld create mode 100644 libopencm3/lib/stm32/l1/stm32l15xxc.ld create mode 100644 libopencm3/lib/stm32/l1/stm32l15xxd.ld create mode 100644 libopencm3/lib/stm32/l1/timer.c create mode 100644 libopencm3/lib/stm32/l1/usart.c create mode 100644 libopencm3/lib/usb/usb.c create mode 100644 libopencm3/lib/usb/usb_control.c create mode 100644 libopencm3/lib/usb/usb_f103.c create mode 100644 libopencm3/lib/usb/usb_f107.c create mode 100644 libopencm3/lib/usb/usb_f207.c create mode 100644 libopencm3/lib/usb/usb_fx07_common.c create mode 100644 libopencm3/lib/usb/usb_fx07_common.h create mode 100644 libopencm3/lib/usb/usb_msc.c create mode 100644 libopencm3/lib/usb/usb_private.h create mode 100644 libopencm3/lib/usb/usb_standard.c (limited to 'libopencm3/lib') diff --git a/libopencm3/lib/Makefile.include b/libopencm3/lib/Makefile.include new file mode 100644 index 0000000..70fdd5c --- /dev/null +++ b/libopencm3/lib/Makefile.include @@ -0,0 +1,52 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 Piotr Esden-Tempski +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +# Be silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +Q := @ +endif + +# common objects +OBJS += vector.o systick.o scb.o nvic.o assert.o sync.o dwt.o + +all: $(SRCLIBDIR)/$(LIBNAME).a + +$(SRCLIBDIR)/$(LIBNAME).a: $(SRCLIBDIR)/$(LIBNAME).ld $(OBJS) + @printf " AR $(LIBNAME).a\n" + $(Q)$(AR) $(ARFLAGS) "$@" $(OBJS) + +$(SRCLIBDIR)/$(LIBNAME).ld: $(LIBNAME).ld + @printf " CP $(LIBNAME).ld\n" + $(Q)cp $^ "$@" + $(Q)if [ -f $(LIBNAME)_rom_to_ram.ld ]; then cp $(LIBNAME)_rom_to_ram.ld $(SRCLIBDIR); fi + +%.o: %.c + @printf " CC $( + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +void __attribute__((weak)) cm3_assert_failed(void) +{ + while (1); +} + +void __attribute__((weak)) cm3_assert_failed_verbose( + const char *file __attribute__((unused)), + int line __attribute__((unused)), + const char *func __attribute__((unused)), + const char *assert_expr __attribute__((unused))) +{ + cm3_assert_failed(); +} diff --git a/libopencm3/lib/cm3/dwt.c b/libopencm3/lib/cm3/dwt.c new file mode 100644 index 0000000..fe7c261 --- /dev/null +++ b/libopencm3/lib/cm3/dwt.c @@ -0,0 +1,77 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @brief DebugTrace Enable the CPU cycle counter + * + * This function will try to enable the CPU cycle counter that is intended for + * benchmarking performance of the code. If function fails, the cycle counter + * isn't available on this architecture. + * + * @returnd true, if success + */ +bool dwt_enable_cycle_counter(void) +{ +#if defined(__ARM_ARCH_6M__) + return false; /* Not supported on ARMv6M */ +#endif /* defined(__ARM_ARCH_6M__) */ + +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + /* Note TRCENA is for 7M and above*/ + SCS_DEMCR |= SCS_DEMCR_TRCENA; + if (DWT_CTRL & DWT_CTRL_NOCYCCNT) { + return false; /* Not supported in implementation */ + } + + DWT_CYCCNT = 0; + DWT_CTRL |= DWT_CTRL_CYCCNTENA; + return true; +#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */ + + /* not supported on other architectures */ + return false; +} +/*---------------------------------------------------------------------------*/ +/** @brief DebugTrace Read the CPU cycle counter + * + * This function reads the core cycle counter if it is enabled. It is the + * fastest clock running on the system. + * + * @note The CPU cycle counter must be enabled by @ref dwt_enable_cycle_counter + * + * @returns 0 if cycle counter is not supported or enabled, the cycle counter + * value otherwise. + */ +uint32_t dwt_read_cycle_counter(void) +{ +#if defined(__ARM_ARCH_6M__) + return 0; /* Not supported on ARMv6M */ +#endif /* defined(__ARM_ARCH_6M__) */ + +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + if (DWT_CTRL & DWT_CTRL_CYCCNTENA) { + return DWT_CYCCNT; + } else { + return 0; /* not supported or enabled */ + } +#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */ +} diff --git a/libopencm3/lib/cm3/nvic.c b/libopencm3/lib/cm3/nvic.c new file mode 100644 index 0000000..6c2188a --- /dev/null +++ b/libopencm3/lib/cm3/nvic.c @@ -0,0 +1,199 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2012 Fergus Noble + * Copyright (C) 2012 Benjamin Vernoux + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/** @defgroup CM3_nvic_file NVIC + * + * @ingroup CM3_files + * + * @brief libopencm3 Cortex Nested Vectored Interrupt Controller + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 Thomas Otto + * @author @htmlonly © @endhtmlonly 2012 Fergus Noble + * + * + * @date 18 August 2012 + * + * Cortex processors provide 14 cortex-defined interrupts (NMI, usage faults, + * systicks etc.) and varying numbers of implementation defined interrupts + * (typically peripherial interrupts and DMA). + * + * @see Cortex-M3 Devices Generic User Guide + * @see STM32F10xxx Cortex-M3 programming manual + * + * LGPL License Terms @ref lgpl_license +*/ +/**@{*/ + +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Enable Interrupt + * + * Enables a user interrupt. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + */ + +void nvic_enable_irq(uint8_t irqn) +{ + NVIC_ISER(irqn / 32) = (1 << (irqn % 32)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Disable Interrupt + * + * Disables a user interrupt. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + */ + +void nvic_disable_irq(uint8_t irqn) +{ + NVIC_ICER(irqn / 32) = (1 << (irqn % 32)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Return Pending Interrupt + * + * True if the interrupt has occurred and is waiting for service. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + * @return Boolean. Interrupt pending. + */ + +uint8_t nvic_get_pending_irq(uint8_t irqn) +{ + return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Set Pending Interrupt + * + * Force a user interrupt to a pending state. This has no effect if the + * interrupt is already pending. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + */ + +void nvic_set_pending_irq(uint8_t irqn) +{ + NVIC_ISPR(irqn / 32) = (1 << (irqn % 32)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Clear Pending Interrupt + * + * Force remove a user interrupt from a pending state. This has no effect if + * the interrupt is actively being serviced. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + */ + +void nvic_clear_pending_irq(uint8_t irqn) +{ + NVIC_ICPR(irqn / 32) = (1 << (irqn % 32)); +} + + + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Return Enabled Interrupt + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + * @return Boolean. Interrupt enabled. + */ + +uint8_t nvic_get_irq_enabled(uint8_t irqn) +{ + return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Set Interrupt Priority + * + * CM3, CM4: + * + * There are 16 priority levels only, given by the upper four bits of the + * priority byte, as required by ARM standards. The priority levels are + * interpreted according to the pre-emptive priority grouping set in the + * SCB Application Interrupt and Reset Control Register (SCB_AIRCR), as done + * in @ref scb_set_priority_grouping. + * + * CM0: + * + * There are 4 priority levels only, given by the upper two bits of the + * priority byte, as required by ARM standards. No grouping available. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + * @param[in] priority Unsigned int8. Interrupt priority (0 ... 255 in steps of + * 16) + */ + +void nvic_set_priority(uint8_t irqn, uint8_t priority) +{ + /* code from lpc43xx/nvic.c -- this is quite a hack and alludes to the + * negative interrupt numbers assigned to the system interrupts. better + * handling would mean signed integers. */ + if (irqn >= NVIC_IRQ_COUNT) { + /* Cortex-M system interrupts */ + SCS_SHPR((irqn & 0xF) - 4) = priority; + } else { + /* Device specific interrupts */ + NVIC_IPR(irqn) = priority; + } +} + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Return Active Interrupt + * + * Interrupt has occurred and is currently being serviced. + * + * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint + * @return Boolean. Interrupt active. + */ + +uint8_t nvic_get_active_irq(uint8_t irqn) +{ + return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief NVIC Software Trigger Interrupt + * + * Generate an interrupt from software. This has no effect for unprivileged + * access unless the privilege level has been elevated through the System + * Control Registers. + * + * @param[in] irqn Unsigned int16. Interrupt number (0 ... 239) + */ + +void nvic_generate_software_interrupt(uint16_t irqn) +{ + if (irqn <= 239) { + NVIC_STIR |= irqn; + } +} +#endif +/**@}*/ diff --git a/libopencm3/lib/cm3/scb.c b/libopencm3/lib/cm3/scb.c new file mode 100644 index 0000000..8c5a2f3 --- /dev/null +++ b/libopencm3/lib/cm3/scb.c @@ -0,0 +1,47 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +void scb_reset_core(void) +{ + SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET; + + while (1); +} +#endif + +void scb_reset_system(void) +{ + SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ; + + while (1); +} + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +void scb_set_priority_grouping(uint32_t prigroup) +{ + SCB_AIRCR = SCB_AIRCR_VECTKEY | prigroup; +} +#endif diff --git a/libopencm3/lib/cm3/sync.c b/libopencm3/lib/cm3/sync.c new file mode 100644 index 0000000..906138a --- /dev/null +++ b/libopencm3/lib/cm3/sync.c @@ -0,0 +1,73 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/* DMB is supported on CM0 */ +void __dmb() +{ + __asm__ volatile ("dmb"); +} + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + +uint32_t __ldrex(volatile uint32_t *addr) +{ + uint32_t res; + __asm__ volatile ("ldrex %0, [%1]" : "=r" (res) : "r" (addr)); + return res; +} + +uint32_t __strex(uint32_t val, volatile uint32_t *addr) +{ + uint32_t res; + __asm__ volatile ("strex %0, %2, [%1]" + : "=&r" (res) : "r" (addr), "r" (val)); + return res; +} + +void mutex_lock(mutex_t *m) +{ + uint32_t status = 0; + + do { + /* Wait until the mutex is unlocked. */ + while (__ldrex(m) != MUTEX_UNLOCKED); + + /* Try to acquire it. */ + status = __strex(MUTEX_LOCKED, m); + + /* Did we get it? If not then try again. */ + } while (status != 0); + + /* Execute the mysterious Data Memory Barrier instruction! */ + __dmb(); +} + +void mutex_unlock(mutex_t *m) +{ + /* Ensure accesses to protected resource are finished */ + __dmb(); + + /* Free the lock. */ + *m = MUTEX_UNLOCKED; +} + +#endif diff --git a/libopencm3/lib/cm3/systick.c b/libopencm3/lib/cm3/systick.c new file mode 100644 index 0000000..a99593b --- /dev/null +++ b/libopencm3/lib/cm3/systick.c @@ -0,0 +1,203 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2012 Benjamin Vernoux + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/** @defgroup CM3_systick_file SysTick + * + * @ingroup CM3_files + * + * @brief libopencm3 Cortex System Tick Timer + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 Thomas Otto + * + * @date 19 August 2012 + * + * This library supports the System Tick timer in ARM Cortex Microcontrollers. + * + * The System Tick timer is part of the ARM Cortex core. It is a 24 bit + * down counter that can be configured with an automatical reload value. + * + * LGPL License Terms @ref lgpl_license + */ + +/**@{*/ +#include + +/*---------------------------------------------------------------------------*/ +/** @brief SysTick Set the Automatic Reload Value. + * + * The counter is set to the reload value when the counter starts and after it + * reaches zero. + * + * @note The systick counter value might be undefined upon startup. To get + * predictable behavior, it is a good idea to set or clear the counter after + * set reload. @seealso systick_clear + * + * @param[in] value uint32_t. 24 bit reload value. + */ + +void systick_set_reload(uint32_t value) +{ + STK_RVR = (value & STK_RVR_RELOAD); +} + +/*---------------------------------------------------------------------------*/ +/** @brief SysTick Read the Automatic Reload Value. + * + * @returns 24 bit reload value as uint32_t. + */ + +uint32_t systick_get_reload(void) +{ + return STK_RVR & STK_RVR_RELOAD; +} + +/** @brief SysTick Set clock and frequency of overflow + * + * This function sets the systick to AHB clock source, and the prescaler to + * generate interrupts with the desired frequency. The function fails, if + * the frequency is too low. + * + * @param[in] freq uint32_t The desired frequency in Hz + * @param[in] ahb uint32_t The current AHB frequency in Hz + * @returns true, if success, false if the desired frequency cannot be set. + */ +bool systick_set_frequency(uint32_t freq, uint32_t ahb) +{ + uint32_t ratio = ahb / freq; + +#if defined(__ARM_ARCH_6M__) + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); +#else + if (ratio >= (STK_RVR_RELOAD * 8)) { + /* This frequency is too slow */ + return false; + } else if (ratio >= STK_RVR_RELOAD) { + ratio /= 8; + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + } else { + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); + } +#endif + systick_set_reload(ratio - 1); + return true; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the current SysTick counter value. + * + * @returns 24 bit current value as uint32_t. + */ + +uint32_t systick_get_value(void) +{ + return STK_CVR & STK_CVR_CURRENT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the SysTick Clock Source. + * + * The clock source can be either the AHB clock or the same clock divided by 8. + * + * @param[in] clocksource uint8_t. Clock source from @ref systick_clksource. + */ + +void systick_set_clocksource(uint8_t clocksource) +{ + STK_CSR = (STK_CSR & ~STK_CSR_CLKSOURCE) | + (clocksource & STK_CSR_CLKSOURCE); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable SysTick Interrupt. + * + */ + +void systick_interrupt_enable(void) +{ + STK_CSR |= STK_CSR_TICKINT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable SysTick Interrupt. + * + */ + +void systick_interrupt_disable(void) +{ + STK_CSR &= ~STK_CSR_TICKINT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable SysTick Counter. + * + */ + +void systick_counter_enable(void) +{ + STK_CSR |= STK_CSR_ENABLE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable SysTick Counter. + * + */ + +void systick_counter_disable(void) +{ + STK_CSR &= ~STK_CSR_ENABLE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SysTick Read the Counter Flag. + * + * The count flag is set when the timer count becomes zero, and is cleared when + * the flag is read. + * + * @returns Boolean if flag set. + */ + +uint8_t systick_get_countflag(void) +{ + return (STK_CSR & STK_CSR_COUNTFLAG) ? 1 : 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SysTick Clear counter Value. + * + * The counter value is cleared. Useful for well defined startup. + */ + +void systick_clear(void) +{ + STK_CVR = 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SysTick Get Calibration Value + * + * @returns Current calibration value + */ +uint32_t systick_get_calib(void) +{ + return STK_CALIB & STK_CALIB_TENMS; +} +/**@}*/ + diff --git a/libopencm3/lib/cm3/vector.c b/libopencm3/lib/cm3/vector.c new file mode 100644 index 0000000..4523d31 --- /dev/null +++ b/libopencm3/lib/cm3/vector.c @@ -0,0 +1,121 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski , + * Copyright (C) 2012 chrysn + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/* load optional platform dependent initialization routines */ +#include "../dispatch/vector_chipset.c" +/* load the weak symbols for IRQ_HANDLERS */ +#include "../dispatch/vector_nvic.c" + +/* Symbols exported by the linker script(s): */ +extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack; +typedef void (*funcp_t) (void); +extern funcp_t __preinit_array_start, __preinit_array_end; +extern funcp_t __init_array_start, __init_array_end; +extern funcp_t __fini_array_start, __fini_array_end; + +void main(void); +void blocking_handler(void); +void null_handler(void); + +__attribute__ ((section(".vectors"))) +vector_table_t vector_table = { + .initial_sp_value = &_stack, + .reset = reset_handler, + .nmi = nmi_handler, + .hard_fault = hard_fault_handler, + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + .memory_manage_fault = mem_manage_handler, + .bus_fault = bus_fault_handler, + .usage_fault = usage_fault_handler, + .debug_monitor = debug_monitor_handler, +#endif + + .sv_call = sv_call_handler, + .pend_sv = pend_sv_handler, + .systick = sys_tick_handler, + .irq = { + IRQ_HANDLERS + } +}; + +void WEAK __attribute__ ((naked)) reset_handler(void) +{ + volatile unsigned *src, *dest; + funcp_t *fp; + + for (src = &_data_loadaddr, dest = &_data; + dest < &_edata; + src++, dest++) { + *dest = *src; + } + + while (dest < &_ebss) { + *dest++ = 0; + } + + /* Constructors. */ + for (fp = &__preinit_array_start; fp < &__preinit_array_end; fp++) { + (*fp)(); + } + for (fp = &__init_array_start; fp < &__init_array_end; fp++) { + (*fp)(); + } + + /* might be provided by platform specific vector.c */ + pre_main(); + + /* Call the application's entry point. */ + main(); + + /* Destructors. */ + for (fp = &__fini_array_start; fp < &__fini_array_end; fp++) { + (*fp)(); + } + +} + +void blocking_handler(void) +{ + while (1); +} + +void null_handler(void) +{ + /* Do nothing. */ +} + +#pragma weak nmi_handler = null_handler +#pragma weak hard_fault_handler = blocking_handler +#pragma weak sv_call_handler = null_handler +#pragma weak pend_sv_handler = null_handler +#pragma weak sys_tick_handler = null_handler + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#pragma weak mem_manage_handler = blocking_handler +#pragma weak bus_fault_handler = blocking_handler +#pragma weak usage_fault_handler = blocking_handler +#pragma weak debug_monitor_handler = null_handler +#endif + diff --git a/libopencm3/lib/dispatch/vector_chipset.c b/libopencm3/lib/dispatch/vector_chipset.c new file mode 100644 index 0000000..c491c2f --- /dev/null +++ b/libopencm3/lib/dispatch/vector_chipset.c @@ -0,0 +1,12 @@ +#if defined(STM32F3) +# include "../stm32/f3/vector_chipset.c" +#elif defined(STM32F4) +# include "../stm32/f4/vector_chipset.c" +#elif defined(LPC43XX_M4) +# include "../lpc43xx/m4/vector_chipset.c" + +#else + +static void pre_main(void) {} + +#endif diff --git a/libopencm3/lib/efm32/efm32g/Makefile b/libopencm3/lib/efm32/efm32g/Makefile new file mode 100644 index 0000000..7a644b2 --- /dev/null +++ b/libopencm3/lib/efm32/efm32g/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 chrysn +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_efm32g +SRCLIBDIR ?= ../.. +FAMILY = EFM32G + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -D$(FAMILY) +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = + +VPATH += ../:../../cm3 + +include ../../Makefile.include + diff --git a/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld new file mode 100644 index 0000000..87d6ee6 --- /dev/null +++ b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for EFM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld new file mode 100644 index 0000000..09c6fb0 --- /dev/null +++ b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld @@ -0,0 +1,15 @@ +/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from + * d0034_efm32tg_reference_manual.pdf figure 5.2. + * + * the origins and memory structure are constant over all tinygeckos, but the + * MEMORY section requires the use of constants, and has thus to be duplicated + * over the chip variants. + * */ + +MEMORY +{ + rom (rx) : ORIGIN = 0, LENGTH = 128k + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16k +} + +INCLUDE libopencm3_efm32g.ld; diff --git a/libopencm3/lib/efm32/efm32gg/Makefile b/libopencm3/lib/efm32/efm32gg/Makefile new file mode 100644 index 0000000..fdfe6e7 --- /dev/null +++ b/libopencm3/lib/efm32/efm32gg/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 chrysn +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_efm32gg +SRCLIBDIR ?= ../.. +FAMILY = EFM32GG + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -D$(FAMILY) +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = + +VPATH += ../:../../cm3 + +include ../../Makefile.include + diff --git a/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld new file mode 100644 index 0000000..87d6ee6 --- /dev/null +++ b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for EFM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld new file mode 100644 index 0000000..694e17a --- /dev/null +++ b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld @@ -0,0 +1,15 @@ +/* lengths from d046_efm32gg990_datasheet.pdf table 1.1, offset from + * d0034_efm32tg_reference_manual.pdf figure 5.2. + * + * the origins and memory structure are constant over all giantgeckos, but the + * MEMORY section requires the use of constants, and has thus to be duplicated + * over the chip variants. + * */ + +MEMORY +{ + rom (rx) : ORIGIN = 0, LENGTH = 1024k + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128k +} + +INCLUDE libopencm3_efm32gg.ld; diff --git a/libopencm3/lib/efm32/efm32lg/Makefile b/libopencm3/lib/efm32/efm32lg/Makefile new file mode 100644 index 0000000..07a8e45 --- /dev/null +++ b/libopencm3/lib/efm32/efm32lg/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 chrysn +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_efm32lg +SRCLIBDIR ?= ../.. +FAMILY = EFM32LG + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -D$(FAMILY) +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = + +VPATH += ../:../../cm3 + +include ../../Makefile.include + diff --git a/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld b/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld new file mode 100644 index 0000000..87d6ee6 --- /dev/null +++ b/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for EFM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/efm32/efm32tg/Makefile b/libopencm3/lib/efm32/efm32tg/Makefile new file mode 100644 index 0000000..46de193 --- /dev/null +++ b/libopencm3/lib/efm32/efm32tg/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 chrysn +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_efm32tg +SRCLIBDIR ?= ../.. +FAMILY = EFM32TG + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -D$(FAMILY) +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = + +VPATH += ../:../../cm3 + +include ../../Makefile.include + diff --git a/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld new file mode 100644 index 0000000..87d6ee6 --- /dev/null +++ b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for EFM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld new file mode 100644 index 0000000..2cb8daf --- /dev/null +++ b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld @@ -0,0 +1,15 @@ +/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from + * d0034_efm32tg_reference_manual.pdf figure 5.2. + * + * the origins and memory structure are constant over all tinygeckos, but the + * MEMORY section requires the use of constants, and has thus to be duplicated + * over the chip variants. + * */ + +MEMORY +{ + rom (rx) : ORIGIN = 0, LENGTH = 32k + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4k +} + +INCLUDE libopencm3_efm32tg.ld; diff --git a/libopencm3/lib/ethernet/mac.c b/libopencm3/lib/ethernet/mac.c new file mode 100644 index 0000000..3b7db12 --- /dev/null +++ b/libopencm3/lib/ethernet/mac.c @@ -0,0 +1,43 @@ +/** @defgroup ethernet_mac_file MAC Generic Drivers + * + * @ingroup ETH + * + * @brief Ethernet MAC Generic Drivers + * + * @version 1.0.0 + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 1 September 2013 + * + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/**@{*/ + + +/*---------------------------------------------------------------------------*/ + +/**@}*/ diff --git a/libopencm3/lib/ethernet/mac_stm32fxx7.c b/libopencm3/lib/ethernet/mac_stm32fxx7.c new file mode 100644 index 0000000..16f76a8 --- /dev/null +++ b/libopencm3/lib/ethernet/mac_stm32fxx7.c @@ -0,0 +1,378 @@ +/** @defgroup ethernet_mac_stm32fxx7_file MAC STM32Fxx7 + * + * @ingroup ETH + * + * @brief Ethernet MAC STM32Fxx7 Drivers + * + * @version 1.0.0 + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 1 September 2013 + * + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include + +/**@{*/ + +uint32_t TxBD; +uint32_t RxBD; + +/*---------------------------------------------------------------------------*/ +/** @brief Set MAC to the PHY + * + * @param[in] mac uint8_t* Desired MAC + */ +void eth_set_mac(uint8_t *mac) +{ + ETH_MACAHR(0) = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4] | + ETH_MACA0HR_MACA0H; + ETH_MACALR(0) = ((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) | + ((uint32_t)mac[1] << 8) | mac[0]; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Initialize descriptors + * + * @param[in] buf uint8_t* Buffer for the descriptors + * @param[in] nTx uint32_t Count of Transmit Descriptors + * @param[in] nRx uint32_t Count of Receive Descriptors + * @param[in] cTx uint32_t Bytes in each Transmit Descriptor + * @param[in] cRx uint32_t Bytes in each Receive Descriptor + * @param[in] isext bool true, if extended descriptors should be used + */ +void eth_desc_init(uint8_t *buf, uint32_t nTx, uint32_t nRx, uint32_t cTx, + uint32_t cRx, bool isext) +{ + memset(buf, 0, nTx * cTx + nRx * cRx); + + uint32_t bd = (uint32_t)buf; + uint32_t sz = isext ? ETH_DES_EXT_SIZE : ETH_DES_STD_SIZE; + + /* enable / disable extended frames */ + if (isext) { + ETH_DMABMR |= ETH_DMABMR_EDFE; + } else { + ETH_DMABMR &= ~ETH_DMABMR_EDFE; + } + + TxBD = bd; + while (--nTx > 0) { + ETH_DES0(bd) = ETH_TDES0_TCH; + ETH_DES2(bd) = bd + sz; + ETH_DES3(bd) = bd + sz + cTx; + bd = ETH_DES3(bd); + } + + ETH_DES0(bd) = ETH_TDES0_TCH; + ETH_DES2(bd) = bd + sz; + ETH_DES3(bd) = TxBD; + bd += sz + cTx; + + RxBD = bd; + while (--nRx > 0) { + ETH_DES0(bd) = ETH_RDES0_OWN; + ETH_DES1(bd) = ETH_RDES1_RCH | cRx; + ETH_DES2(bd) = bd + sz; + ETH_DES3(bd) = bd + sz + cRx; + bd = ETH_DES3(bd); + } + + ETH_DES0(bd) = ETH_RDES0_OWN; + ETH_DES1(bd) = ETH_RDES1_RCH | cRx; + ETH_DES2(bd) = bd + sz; + ETH_DES3(bd) = RxBD; + + ETH_DMARDLAR = (uint32_t) RxBD; + ETH_DMATDLAR = (uint32_t) TxBD; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Transmit packet + * + * @param[in] ppkt uint8_t* Pointer to the beginning of the packet + * @param[in] n uint32_t Size of the packet + * @returns bool true, if success + */ +bool eth_tx(uint8_t *ppkt, uint32_t n) +{ + if (ETH_DES0(TxBD) & ETH_TDES0_OWN) { + return false; + } + + memcpy((void *)ETH_DES2(TxBD), ppkt, n); + + ETH_DES1(TxBD) = n & ETH_TDES1_TBS1; + ETH_DES0(TxBD) |= ETH_TDES0_LS | ETH_TDES0_FS | ETH_TDES0_OWN; + TxBD = ETH_DES3(TxBD); + + if (ETH_DMASR & ETH_DMASR_TBUS) { + ETH_DMASR = ETH_DMASR_TBUS; + ETH_DMATPDR = 0; + } + + return true; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Receive packet + * + * @param[inout] ppkt uint8_t* Pointer to the data buffer where to store data + * @param[inout] len uint32_t* Pointer to the variable with the packet length + * @param[in] maxlen uint32_t Maximum length of the packet + * @returns bool true, if the buffer contains readed packet data + */ +bool eth_rx(uint8_t *ppkt, uint32_t *len, uint32_t maxlen) +{ + bool fs = false; + bool ls = false; + bool overrun = false; + uint32_t l = 0; + + while (!(ETH_DES0(RxBD) & ETH_RDES0_OWN) && !ls) { + l = (ETH_DES0(RxBD) & ETH_RDES0_FL) >> ETH_RDES0_FL_SHIFT; + + fs |= ETH_DES0(RxBD) & ETH_RDES0_FS; + ls |= ETH_DES0(RxBD) & ETH_RDES0_LS; + /* frame buffer overrun ?*/ + overrun |= fs && (maxlen < l); + + if (fs && !overrun) { + memcpy(ppkt, (void *)ETH_DES2(RxBD), l); + ppkt += l; + *len += l; + maxlen -= l; + } + + ETH_DES0(RxBD) = ETH_RDES0_OWN; + RxBD = ETH_DES3(RxBD); + } + + if (ETH_DMASR & ETH_DMASR_RBUS) { + ETH_DMASR = ETH_DMASR_RBUS; + ETH_DMARPDR = 0; + } + + return fs && ls && !overrun; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Start the Ethernet DMA processing + */ +void eth_start(void) +{ + ETH_MACCR |= ETH_MACCR_TE; + ETH_DMAOMR |= ETH_DMAOMR_FTF; + ETH_MACCR |= ETH_MACCR_RE; + + ETH_DMAOMR |= ETH_DMAOMR_ST; + ETH_DMAOMR |= ETH_DMAOMR_SR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Initialize ethernet + * + * This function will initialize ethernet, set up clocks, and initialize DMA. + * + * @param[in] clock enum eth_clk Core clock speed + */ +void eth_init(enum eth_clk clock) +{ + ETH_MACMIIAR = clock; + phy_reset(); + + ETH_MACCR = ETH_MACCR_CSTF | ETH_MACCR_FES | ETH_MACCR_DM | + ETH_MACCR_APCS | ETH_MACCR_RD; + ETH_MACFFR = ETH_MACFFR_RA | ETH_MACFFR_PM; + ETH_MACHTHR = 0; /* pass all frames */ + ETH_MACHTLR = 0; + ETH_MACFCR = (0x100 << ETH_MACFCR_PT_SHIFT); + ETH_MACVLANTR = 0; + ETH_DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_DFRF | + ETH_DMAOMR_TSF | ETH_DMAOMR_FEF | ETH_DMAOMR_OSF; + ETH_DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_FB | + (32 << ETH_DMABMR_RDP_SHIFT) | (32 << ETH_DMABMR_PBL_SHIFT) | + ETH_DMABMR_PM_2_1 | ETH_DMABMR_USP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the Ethernet IRQ + * + * @param[in] reason uint32_t Which irq will be enabled + */ +void eth_irq_enable(uint32_t reason) +{ + ETH_DMAIER |= reason; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the Ethernet IRQ + * + * @param[in] reason uint32_t Which irq will be disabled + */ +void eth_irq_disable(uint32_t reason) +{ + ETH_DMAIER &= ~reason; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Check if IRQ is pending + * + * @param[in] reason uint32_t Which irq type has to be tested + * @returns bool true, if IRQ is pending + */ +bool eth_irq_is_pending(uint32_t reason) +{ + return (ETH_DMASR & reason) != 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Check if IRQ is pending, and acknowledge it + * + * @param[in] reason uint32_t Which irq type has to be tested + * @returns bool true, if IRQ is pending + */ +bool eth_irq_ack_pending(uint32_t reason) +{ + reason &= ETH_DMASR; + ETH_DMASR = reason; + return reason != 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable checksum offload feature + * + * This function will enable the Checksum offload feature for all of the + * transmit descriptors. Note to use this feature, descriptors must be in + * extended format. + */ +void eth_enable_checksum_offload(void) +{ + uint32_t tab = TxBD; + do { + ETH_DES0(tab) |= ETH_TDES0_CIC_IPPLPH; + tab = ETH_DES3(tab); + } + while (tab != TxBD); + + ETH_MACCR |= ETH_MACCR_IPCO; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Process pending SMI transaction and wait to be done. + */ +static void eth_smi_transact(void) +{ + /* Begin transaction. */ + ETH_MACMIIAR |= ETH_MACMIIAR_MB; + + /* Wait for not busy. */ + while (ETH_MACMIIAR & ETH_MACMIIAR_MB); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Write 16-bit register to the PHY + * + * @param[in] phy uint8_t ID of the PHY (defaults to 1) + * @param[in] reg uint8_t Register address + * @param[in] data uint16_t Data to write + */ +void eth_smi_write(uint8_t phy, uint8_t reg, uint16_t data) +{ + /* Write operation MW=1*/ + ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */ + (phy << ETH_MACMIIAR_PA_SHIFT) | + (reg << ETH_MACMIIAR_MR_SHIFT) | + ETH_MACMIIAR_MW; + + ETH_MACMIIDR = data & ETH_MACMIIDR_MD; + + eth_smi_transact(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read the 16-bit register from the PHY + * + * @param[in] phy uint8_t ID of the PHY (defaults to 1) + * @param[in] reg uint8_t Register address + * @returns uint16_t Readed data + */ +uint16_t eth_smi_read(uint8_t phy, uint8_t reg) +{ + /* Read operation MW=0*/ + ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */ + (phy << ETH_MACMIIAR_PA_SHIFT) | + (reg << ETH_MACMIIAR_MR_SHIFT); + + eth_smi_transact(); + + return (uint16_t)(ETH_MACMIIDR & ETH_MACMIIDR_MD); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Process the bit-operation on PHY register + * + * @param[in] phy uint8_t ID of the PHY (defaults to 1) + * @param[in] reg uint8_t Register address + * @param[in] bits uint16_t Bits that have to be set (or'ed) + * @param[in] mask uint16_t Bits that have to be clear (and'ed) + */ +void eth_smi_bit_op(uint8_t phy, uint8_t reg, uint16_t bits, uint16_t mask) +{ + uint16_t val = eth_smi_read(phy, reg); + eth_smi_write(phy, reg, (val & mask) | bits); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear bits in the register + * + * @param[in] phy uint8_t ID of the PHY (defaults to 1) + * @param[in] reg uint8_t Register address + * @param[in] clearbits uint16_t Bits that have to be cleared + */ +void eth_smi_bit_clear(uint8_t phy, uint8_t reg, uint16_t clearbits) +{ + uint16_t val = eth_smi_read(phy, reg); + eth_smi_write(phy, reg, val & (uint16_t)~(clearbits)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set bits in the register + * + * @param[in] phy uint8_t ID of the PHY (defaults to 1) + * @param[in] reg uint8_t Register address + * @param[in] bits uint16_t Bits that have to be set (or'ed) + */ +void eth_smi_bit_set(uint8_t phy, uint8_t reg, uint16_t setbits) +{ + uint16_t val = eth_smi_read(phy, reg); + eth_smi_write(phy, reg, val | setbits); +} + +/*---------------------------------------------------------------------------*/ + +/**@}*/ diff --git a/libopencm3/lib/ethernet/phy.c b/libopencm3/lib/ethernet/phy.c new file mode 100644 index 0000000..4866198 --- /dev/null +++ b/libopencm3/lib/ethernet/phy.c @@ -0,0 +1,64 @@ +/** @defgroup ethernet_phy_file PHY Generic Drivers + * + * @ingroup ETH + * + * @brief Ethernet PHY Generic Drivers + * + * @version 1.0.0 + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 1 September 2013 + * + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Is the link up ? + * + * @returns bool true, if link is up + */ +bool phy_link_isup(void) +{ + return eth_smi_read(1, PHY_REG_BSR) & PHY_REG_BSR_UP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset the PHY + * + * Reset the PHY chip and wait for done + */ +void phy_reset(void) +{ + eth_smi_write(1, PHY_REG_BCR, PHY_REG_BCR_RESET); + + while (eth_smi_read(1, PHY_REG_BCR) & PHY_REG_BCR_RESET); +} + +/*---------------------------------------------------------------------------*/ + +/**@}*/ diff --git a/libopencm3/lib/ethernet/phy_ksz8051mll.c b/libopencm3/lib/ethernet/phy_ksz8051mll.c new file mode 100644 index 0000000..1faae4f --- /dev/null +++ b/libopencm3/lib/ethernet/phy_ksz8051mll.c @@ -0,0 +1,89 @@ +/** @defgroup ethernet_phy_ksz8051mll_file PHY KSZ8051MLL + * + * @ingroup ETH + * + * @brief Ethernet PHY STM32Fxx7 Drivers + * + * @version 1.0.0 + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 1 September 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Get the current link status + * + * Retrieve the link speed and duplex status of the link. + * + * @returns ::phy_status Link status + */ +enum phy_status phy_link_status(void) +{ + return eth_smi_read(1, PHY_REG_CR1) & 0x07; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Force autonegotiation + * + * Force the autonegotiation and set link speed and duplex mode of the link + * + * @param[in] mode enum phy_status Desired link status + */ +void phy_autoneg_force(enum phy_status mode) +{ + uint16_t bst = 0; + + if ((mode == LINK_FD_10M) || (mode == LINK_FD_100M) || + (mode == LINK_FD_1000M) || (mode == LINK_FD_10000M)) { + bst |= PHY_REG_BCR_FD; + } + + if ((mode == LINK_FD_100M) || (mode == LINK_FD_100M)) { + bst |= PHY_REG_BCR_100M; + } + + eth_smi_bit_op(1, PHY_REG_BCR, bst, + ~(PHY_REG_BCR_AN | PHY_REG_BCR_100M | PHY_REG_BCR_FD)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the autonegotiation + * + * Enable the autonegotiation of the link speed and duplex mode + */ +void phy_autoneg_enable(void) +{ + eth_smi_bit_set(1, PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST); +} + +/*---------------------------------------------------------------------------*/ + +/**@}*/ diff --git a/libopencm3/lib/lm3s/Makefile b/libopencm3/lib/lm3s/Makefile new file mode 100644 index 0000000..353183d --- /dev/null +++ b/libopencm3/lib/lm3s/Makefile @@ -0,0 +1,40 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lm3s +SRCLIBDIR ?= .. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DLM3S +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o vector.o assert.o + +VPATH += ../cm3 + +include ../Makefile.include diff --git a/libopencm3/lib/lm3s/gpio.c b/libopencm3/lib/lm3s/gpio.c new file mode 100644 index 0000000..e0dd264 --- /dev/null +++ b/libopencm3/lib/lm3s/gpio.c @@ -0,0 +1,52 @@ +/** @defgroup gpio_file General Purpose I/O + +@brief LM3S General Purpose I/O + +@ingroup LM3Sxx + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2011 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +void gpio_set(uint32_t gpioport, uint8_t gpios) +{ + /* ipaddr[9:2] mask the bits to be set, hence the array index */ + GPIO_DATA(gpioport)[gpios] = 0xff; +} + +void gpio_clear(uint32_t gpioport, uint8_t gpios) +{ + GPIO_DATA(gpioport)[gpios] = 0; +} + +/**@}*/ + diff --git a/libopencm3/lib/lm3s/libopencm3_lm3s.ld b/libopencm3/lib/lm3s/libopencm3_lm3s.ld new file mode 100644 index 0000000..6c8c7f2 --- /dev/null +++ b/libopencm3/lib/lm3s/libopencm3_lm3s.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LM3S targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/lm4f/Makefile b/libopencm3/lib/lm4f/Makefile new file mode 100644 index 0000000..6b83b0f --- /dev/null +++ b/libopencm3/lib/lm4f/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2013 Alexandru Gagniuc +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lm4f +SRCLIBDIR ?= .. + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../include -fno-common \ + -mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DLM4F +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o vector.o assert.o systemcontrol.o rcc.o uart.o \ + usb_lm4f.o usb.o usb_control.o usb_standard.o + +VPATH += ../usb:../cm3 + +include ../Makefile.include diff --git a/libopencm3/lib/lm4f/gpio.c b/libopencm3/lib/lm4f/gpio.c new file mode 100644 index 0000000..22399bd --- /dev/null +++ b/libopencm3/lib/lm4f/gpio.c @@ -0,0 +1,598 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * Copyright (C) 2013 Alexandru Gagniuc + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/** @defgroup gpio_file GPIO + * + * + * @ingroup LM4Fxx + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2011 + * Gareth McMullin + * @author @htmlonly © @endhtmlonly 2013 + * Alexandru Gagniuc + * + * @date 16 March 2013 + * + * LGPL License Terms @ref lgpl_license + * + * @brief libopencm3 LM4F General Purpose I/O + * + * The LM4F GPIO API provides functionality for accessing the GPIO pins of the + * LM4F. + * + * @attention @code An important aspect to consider is that libopencm3 uses the + * AHB aperture for accessing the GPIO registers on the LM4F. The AHB must be + * explicitly enabled with a call to gpio_enable_ahb_aperture() before accessing + * any GPIO functionality. + * @endcode + * + * Please see the individual GPIO modules for more details. To use the GPIO, the + * gpio.h header needs to be included: + * @code{.c} + * #include + * @endcode + */ + +/**@{*/ + +#include +#include + +/* Value we need to write to unlock the GPIO commit register */ +#define GPIO_LOCK_UNLOCK_CODE 0x4C4F434B + + +/** @defgroup gpio_config GPIO pin configuration + * @ingroup gpio_file + * + * \brief Enabling and configuring GPIO pins + * + * @section gpio_api_enable Enabling GPIO ports + * @attention + * Before accessing GPIO functionality through this API, the AHB aperture for + * GPIO ports must be enabled via a call to @ref gpio_enable_ahb_aperture(). + * Failing to do so will cause a hard fault. + * + * @note + * Once the AHB aperture is enabled, GPIO registers can no longer be accessed + * via the APB aperture. The two apertures are mutually exclusive. + * + * Enabling the AHB aperture only needs to be done once. However, in order to + * access a certain GPIO port, its clock must also be enabled. Enabling the + * GPIO clock needs to be done for every port that will be used. + * + * For example, to enable GPIOA and GPIOD: + * @code{.c} + * // Make sure we can access the GPIO via the AHB aperture + * gpio_enable_ahb_aperture(); + * ... + * // Enable GPIO ports A and D + * periph_clock_enable(RCC_GPIOA); + * periph_clock_enable(RCC_GPIOD); + * @endcode + * + * On reset all ports are configured as digital floating inputs (no pull-up or + * pull-down), except for special function pins. + * + * + * @section gpio_api_in Configuring pins as inputs + * + * Configuring GPIO pins as inputs is done with @ref gpio_mode_setup(), with + * @ref GPIO_MODE_INPUT for the mode parameter. The direction of the pull-up + * must be specified with the same call + * + * For example, PA2, PA3, and PA4 as inputs, with pull-up on PA4: + * @code{.c} + * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2 | GPIO3); + * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO4); + * @endcode + * + * + * @section gpio_api_out Configuring pins as outputs + * + * Output pins have more configuration options than input pins. LM4F pins can be + * configured as either push-pull, or open drain. The drive strength of each pin + * can be adjusted between 2mA, 4mA, or 8mA. Slew-rate control is available when + * the pins are configured to drive 8mA. These extra options can be specified + * with @ref gpio_set_output_config(). + * The default is push-pull configuration with 2mA drive capability. + * + * @note + * @ref gpio_set_output_config() controls different capabilities than the + * similar sounding gpio_set_output_options() from the STM GPIO API. They are + * intentionally named differently to prevent confusion between the two. They + * are API incompatible. + * + * For example, to set PA2 to output push-pull with a drive strength of 8mA: + * @code{.c} + * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2); + * gpio_set_output_config(GPIOA, GPIO_OTYPE_PP, GPIO_DRIVE_8MA, GPIO2); + * @endcode + * + * + * @section gpio_api_analog Configuring pins as analog function + * + * Configuring GPIO pins to their analog function is done with + * @ref gpio_mode_setup(), with @ref GPIO_MODE_ANALOG for the mode parameter. + * + * Suppose PD4 and PD5 are the USB pins. To enable their analog functionality + * (USB D+ and D- in this case), use: + * @code + * // Mux USB pins to their analog function + * gpio_mode_setup(GPIOD, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4 | GPIO5); + * @endcode + * + * @section gpio_api_alf_func Configuring pins as alternate functions + * + * Most pins have alternate functions associated with them. When a pin is set to + * an alternate function, it is multiplexed to one of the dedicated hardware + * peripheral in the chip. The alternate function mapping can be found in the + * part's datasheet, and usually varies between arts of the same family. + * + * Multiplexing a pin, or group of pins to an alternate function is done with + * @ref gpio_set_af(). Because AF0 is not used on the LM4F, passing 0 as the + * alt_func_num parameter will disable the alternate function of the given pins. + * + * @code + * // Mux PB0 and PB1 to AF1 (UART1 TX/RX in this case) + * gpio_set_af(GPIOB, 1, GPIO0 | GPIO1); + * @endcode + * + * @section gpio_api_sfpins Changing configuration of special function pins + * + * On the LM4F, the NMI and JTAG/SWD default to their alternate function. These + * pins cannot normally be committed to GPIO usage. To enable these special + * function pins to be used as GPIO, they must be unlocked. This may be achieved + * via @ref gpio_unlock_commit. Once a special function pin is unlocked, its + * settings may be altered in the usual way. + * + * For example, to unlock the PF0 pin (NMI on the LM4F120): + * @code + * // PF0 is an NMI pin, and needs to be unlocked + * gpio_unlock_commit(GPIOF, GPIO0); + * // Now the pin can be configured + * gpio_mode_setup(RGB_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, btnpins); + * @endcode + */ +/**@{*/ + +/** + * \brief Enable access to GPIO registers via the AHB aperture + * + * All GPIO registers are accessed in libopencm3 via the AHB aperture. It + * provides faster control over the older APB aperture. This aperture must be + * enabled before calling any other gpio_*() function. + * + */ +void gpio_enable_ahb_aperture(void) +{ + SYSCTL_GPIOHBCTL = 0xffffffff; +} + +/** + * \brief Configure a group of pins + * + * Sets the Pin direction, analog/digital mode, and pull-up configuration of + * or a set of GPIO pins on a given GPIO port. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] mode Pin mode (@ref gpio_mode) \n + * - GPIO_MODE_OUTPUT -- Configure pin as output \n + * - GPIO_MODE_INPUT -- Configure pin as input \n + * - GPIO_MODE_ANALOG -- Configure pin as analog function + * @param[in] pullup Pin pullup/pulldown configuration (@ref gpio_pullup) \n + * - GPIO_PUPD_NONE -- Do not pull the pin high or low \n + * - GPIO_PUPD_PULLUP -- Pull the pin high \n + * - GPIO_PUPD_PULLDOWN -- Pull the pin low + * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified + * by OR'ing then together + */ +void gpio_mode_setup(uint32_t gpioport, enum gpio_mode mode, + enum gpio_pullup pullup, uint8_t gpios) +{ + switch (mode) { + case GPIO_MODE_OUTPUT: + GPIO_DIR(gpioport) |= gpios; + GPIO_DEN(gpioport) |= gpios; + GPIO_AMSEL(gpioport) &= ~gpios; + break; + case GPIO_MODE_INPUT: + GPIO_DIR(gpioport) &= ~gpios; + GPIO_DEN(gpioport) |= gpios; + GPIO_AMSEL(gpioport) &= ~gpios; + break; + case GPIO_MODE_ANALOG: + GPIO_DEN(gpioport) &= ~gpios; + GPIO_AMSEL(gpioport) |= gpios; + break; + default: + /* Don't do anything */ + break; + } + + /* + * Setting a bit in the GPIO_PDR register clears the corresponding bit + * in the GPIO_PUR register, and vice-versa. + */ + switch (pullup) { + case GPIO_PUPD_PULLUP: + GPIO_PUR(gpioport) |= gpios; + break; + case GPIO_PUPD_PULLDOWN: + GPIO_PDR(gpioport) |= gpios; + break; + case GPIO_PUPD_NONE: /* Fall through */ + default: + GPIO_PUR(gpioport) &= ~gpios; + GPIO_PDR(gpioport) &= ~gpios; + break; + } +} + +/** + * \brief Configure output parameters of a group of pins + * + * Sets the output configuration and drive strength, of or a set of GPIO pins + * for a set of GPIO pins in output mode. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] otype Output driver configuration (@ref gpio_output_type) \n + * - GPIO_OTYPE_PP -- Configure pin driver as push-pull \n + * - GPIO_OTYPE_OD -- Configure pin driver as open drain + * @param[in] drive Pin drive strength (@ref gpio_drive_strength) \n + * - GPIO_DRIVE_2MA -- 2mA drive \n + * - GPIO_DRIVE_4MA -- 4mA drive \n + * - GPIO_DRIVE_8MA -- 8mA drive \n + * - GPIO_DRIVE_8MA_SLEW_CTL -- 8mA drive with slew rate + * control + * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified + * by OR'ing then together + */ +void gpio_set_output_config(uint32_t gpioport, enum gpio_output_type otype, + enum gpio_drive_strength drive, uint8_t gpios) +{ + if (otype == GPIO_OTYPE_OD) { + GPIO_ODR(gpioport) |= gpios; + } else { + GPIO_ODR(gpioport) &= ~gpios; + } + + /* + * Setting a bit in the GPIO_DRxR register clears the corresponding bit + * in the other GPIO_DRyR registers, and vice-versa. + */ + switch (drive) { + case GPIO_DRIVE_8MA_SLEW_CTL: + GPIO_DR8R(gpioport) |= gpios; + GPIO_SLR(gpioport) |= gpios; + break; + case GPIO_DRIVE_8MA: + GPIO_DR8R(gpioport) |= gpios; + GPIO_SLR(gpioport) &= ~gpios; + break; + case GPIO_DRIVE_4MA: + GPIO_DR4R(gpioport) |= gpios; + break; + case GPIO_DRIVE_2MA: /* Fall through */ + default: + GPIO_DR2R(gpioport) |= gpios; + break; + } +} + +#define PCTL_AF(pin, af) (af << (pin << 2)) +#define PCTL_MASK(pin) PCTL_AF(pin, 0xf) +/** + * \brief Multiplex group of pins to the given alternate function + * + * Mux the pin or group of pins to the given alternate function. Note that a + * number of pins may be set but only with a single AF number. This is useful + * when one or more of a peripheral's pins are assigned to the same alternate + * function. + * + * Because AF0 is not used on the LM4F, passing 0 as the alt_func_num parameter + * will disable the alternate function of the given pins. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] alt_func_num Pin alternate function number or 0 to disable the + * alternate function multiplexing. + * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified + * by OR'ing then together + */ +void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint8_t gpios) +{ + uint32_t pctl32; + uint8_t pin_mask; + int i; + + /* Did we mean to disable the alternate function? */ + if (alt_func_num == 0) { + GPIO_AFSEL(gpioport) &= ~gpios; + return; + } + + /* Enable the alternate function */ + GPIO_AFSEL(gpioport) |= gpios; + /* Alternate functions are digital */ + GPIO_DEN(gpioport) |= gpios; + + /* Now take care of the actual multiplexing */ + pctl32 = GPIO_PCTL(gpioport); + for (i = 0; i < 8; i++) { + pin_mask = (1 << i); + + if (!(gpios & pin_mask)) { + continue; + } + + pctl32 &= ~PCTL_MASK(i); + pctl32 |= PCTL_AF(i, (alt_func_num & 0xf)); + } + + GPIO_PCTL(gpioport) = pctl32; +} + +/** + * \brief Unlock the commit control of a special function pin + * + * Unlocks the commit control of the given pin or group of pins. If a pin is a + * JTAG/SWD or NMI, the pin may then be reconfigured as a GPIO pin. If the pin + * is not locked by default, this has no effect. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified + * by OR'ing then together. + */ +void gpio_unlock_commit(uint32_t gpioport, uint8_t gpios) +{ + /* Unlock the GPIO_CR register */ + GPIO_LOCK(gpioport) = GPIO_LOCK_UNLOCK_CODE; + /* Enable committing changes */ + GPIO_CR(gpioport) |= gpios; + /* Lock the GPIO_CR register */ + GPIO_LOCK(gpioport) = ~GPIO_LOCK_UNLOCK_CODE; +} +/**@}*/ + +/** @defgroup gpio_control GPIO pin control + * @ingroup gpio_file + * + * \brief Controlling GPIO pins + * + * Each I/O port has 8 individually configurable bits. When reading and writing + * data to the GPIO ports, address bits [9:2] mask the pins to be read or + * written. This mechanism makes all GPIO port reads and writes on the LM4F + * atomic operations. The GPIO API takes full advantage of this fact to preserve + * the atomicity of these operations. + * + * Setting or clearing a group of bits can be accomplished with @ref gpio_set() + * and @ref gpio_clear() respectively. These operation use the masking mechanism + * described above to only affect the specified pins. + * + * Sometimes it is more appropriate to read or set the level of a group of pins + * on a port, in one atomic operation. Reading the status can be accomplished + * with @ref gpio_read(). The result is equivalent to reading all the pins, then + * masking only the desired pins; however, the masking is done in hardware, and + * does not require an extra hardware operation. + * + * Writing a group of pins can be accomplished with @ref gpio_write(). The mask + * ('gpios' parameter) is applied in hardware, and the masked pins are not + * affected, regardless of the value of the respective bits written to the GPIO + * port. + * + * Two extra functions are provided, @ref gpio_port_read() and + * @ref gpio_port_write(). They are functionally identical to + * @ref gpio_read (port, GPIO_ALL) and @ref gpio_write (port, GPIO_ALL, val) + * respectively. Hence, they are also atomic. + * + * GPIO pins may be toggled with @ref gpio_toggle(). This function does not + * translate to an atomic operation. + * + * @note + * The @ref gpio_toggle() operation is the only GPIO port operation which is not + * atomic. It involves a read-modify-write cycle. + * + * Suppose PA0, PA1, PA2, and PA3 are to be modified without affecting the other + * pins on port A. This is common when controlling, for example, a 4-bit bus: + * @code{.c} + * // Pins 4,5,6, and 7 are unaffected, regardless of the bits in val + * gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val); + * // Wait a bit then send the other 4 bits + * wait_a_bit(); + * gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val >> 4); + * @endcode + * + * Suppose a LED is connected to PD4, and we want to flash the LED for a brief + * period of time: + * @code + * gpio_set(GPIOD, GPIO4); + * wait_a_bit(); + * gpio_set(GPIOD, GPIO4); + * @endcode + */ +/**@{*/ +/** + * \brief Toggle a Group of Pins + * + * Toggle one or more pins of the given GPIO port. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] gpios Pin identifiers. @ref gpio_pin_id + */ +void gpio_toggle(uint32_t gpioport, uint8_t gpios) +{ + /* The mask makes sure we only toggle the GPIOs we want to */ + GPIO_DATA(gpioport)[gpios] ^= GPIO_ALL; +} +/**@}*/ + + +/** @defgroup gpio_irq GPIO Interrupt control + * @ingroup gpio_file + * + * \brief Configuring interrupts from GPIO pins + * + * GPIO pins can trigger interrupts on either edges or levels. The type of + * trigger can be configured with @ref gpio_configure_int_trigger(). To have an + * event on the given pin generate an interrupt, its interrupt source must be + * unmasked. This can be achieved with @ref gpio_enable_interrupts(). Interrupts + * which are no longer needed can be disabled through + * @ref gpio_disable_interrupts(). + * + * In order for the interrupt to generate an IRQ and a call to the interrupt + * service routine, the interrupt for the GPIO port must be routed through the + * NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is + * needed: + * @code{.c} + * #include + * @endcode + * + * Enabling an interrupt is as simple as configuring the desired trigger, + * unmasking the desired interrupt, and routing the desired GPIO port's + * interrupt through the NVIC. + * @code{.c} + * // Trigger interrupt on each rising edge + * gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, GPIO0 | GPIO4); + * // Unmask the interrupt on those pins + * gpio_enable_interrupts(GPIOF, GPIO0 | GPIO4); + * // Enable the interrupt in the NVIC as well + * nvic_enable_irq(NVIC_GPIOF_IRQ); + * @endcode + * + * After interrupts are properly enabled and routed through the NVIC, when an + * event occurs, the appropriate IRQ flag is set by hardware, and execution + * jumps to the GPIO ISR. The ISR should query the IRQ flags to determine which + * event caused the interrupt. For this, use @ref gpio_is_interrupt_source(), + * with the desired GPIO flag. After one or more interrupt sources are + * serviced, the IRQ flags must be cleared by the ISR. This can be done with + * @ref gpio_clear_interrupt_flag(). + * + * A typical GPIO ISR may look like the following: + * @code{.c} + * void gpiof_isr(void) + * { + * uint8_t serviced_irqs = 0; + * + * // Process individual IRQs + * if (gpio_is_interrupt_source(GPIOF, GPIO0)) { + * process_gpio0_event(); + * serviced_irq |= GPIO0; + * } + * if (gpio_is_interrupt_source(GPIOF, GPIO4)) { + * process_gpio4_event(); + * serviced_irq |= GPIO4; + * } + * + * // Clear the interupt flag for the processed IRQs + * gpio_clear_interrupt_flag(GPIOF, serviced_irqs); + * } + * @endcode + */ +/**@{*/ +/** + * \brief Configure the interrupt trigger on the given GPIO pins + * + * Sets the Pin direction, analog/digital mode, and pull-up configuration of + * or a set of GPIO pins on a given GPIO port. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] trigger Trigger configuration (@ref gpio_trigger) \n + * - GPIO_TRIG_LVL_LOW -- Trigger on low level \n + * - GPIO_TRIG_LVL_HIGH -- Trigger on high level \n + * - GPIO_TRIG_EDGE_FALL -- Trigger on falling edges \n + * - GPIO_TRIG_EDGE_RISE -- Trigger on rising edges \n + * - GPIO_TRIG_EDGE_BOTH -- Trigger on all edges + * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified + * by OR'ing then together + */ +void gpio_configure_trigger(uint32_t gpioport, enum gpio_trigger trigger, + uint8_t gpios) +{ + switch (trigger) { + case GPIO_TRIG_LVL_LOW: + GPIO_IS(gpioport) |= gpios; + GPIO_IEV(gpioport) &= ~gpios; + break; + case GPIO_TRIG_LVL_HIGH: + GPIO_IS(gpioport) |= gpios; + GPIO_IEV(gpioport) |= gpios; + break; + case GPIO_TRIG_EDGE_FALL: + GPIO_IS(gpioport) &= ~gpios; + GPIO_IBE(gpioport) &= ~gpios; + GPIO_IEV(gpioport) &= ~gpios; + break; + case GPIO_TRIG_EDGE_RISE: + GPIO_IS(gpioport) &= ~gpios; + GPIO_IBE(gpioport) &= ~gpios; + GPIO_IEV(gpioport) |= gpios; + break; + case GPIO_TRIG_EDGE_BOTH: + GPIO_IS(gpioport) &= ~gpios; + GPIO_IBE(gpioport) |= gpios; + break; + default: + /* Don't do anything */ + break; + } +} + +/** + * \brief Enable interrupts on specified GPIO pins + * + * Enable interrupts on the specified GPIO pins + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to enable. Any + * combination of pins may be specified by OR'ing them + * together. + */ +void gpio_enable_interrupts(uint32_t gpioport, uint8_t gpios) +{ + GPIO_IM(gpioport) |= gpios; +} + +/** + * \brief Disable interrupts on specified GPIO pins + * + * Disable interrupts on the specified GPIO pins + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] gpioport GPIO block register address base @ref gpio_reg_base + * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to disable. Any + * combination of pins may be specified by OR'ing them + * together. + */ +void gpio_disable_interrupts(uint32_t gpioport, uint8_t gpios) +{ + GPIO_IM(gpioport) |= gpios; +} + +/**@}*/ + +/**@}*/ + diff --git a/libopencm3/lib/lm4f/libopencm3_lm4f.ld b/libopencm3/lib/lm4f/libopencm3_lm4f.ld new file mode 100644 index 0000000..12d939e --- /dev/null +++ b/libopencm3/lib/lm4f/libopencm3_lm4f.ld @@ -0,0 +1,2 @@ +/* Yes, we can simply use the lm3s linker script */ +INCLUDE "libopencm3_lm3s.ld" diff --git a/libopencm3/lib/lm4f/rcc.c b/libopencm3/lib/lm4f/rcc.c new file mode 100644 index 0000000..9b051b3 --- /dev/null +++ b/libopencm3/lib/lm4f/rcc.c @@ -0,0 +1,499 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +/** + * @defgroup rcc_file RCC + * + * @ingroup LM4Fxx + * +@author @htmlonly © @endhtmlonly 2012 +Alexandru Gagniuc + + * \brief libopencm3 LM4F Clock control API + * + * The LM$F clock API provides functionaliity for manipulating the system clock, + * oscillator, and PLL. Functions are provided for fine-grained control of clock + * control registers, while also providing higher level functionality to easily + * configure the main system clock source. + * + * The following code snippet uses fine-grained mechanisms to configures the + * chip to run off an external 16MHz crystal, and use the PLL to derive a clock + * frequency of 80MHz. + * @code{.c} + * // A divisor of 5 gives us a clock of 400/5 = 80MHz + * #define PLLDIV_80MHZ 5 + * + * // Enable the main oscillator + * rcc_enable_main_osc(); + * + * // Make RCC2 override RCC + * rcc_enable_rcc2(); + * + * // Set XTAL value to 16MHz + * rcc_configure_xtal(XTAL_16M); + * // Set the oscillator source as the main oscillator + * rcc_set_osc_source(OSCSRC_MOSC); + * // Enable the PLL + * rcc_pll_on(); + * + * // Change the clock divisor + * rcc_set_pll_divisor(PLLDIV_80MHZ); + * + * // We cannot use the PLL as a clock source until it locks + * rcc_wait_for_pll_ready(); + * // Disable PLL bypass to derive the system clock from the PLL clock + * rcc_pll_bypass_disable(); + * + * // Keep track of frequency + * lm4f_rcc_sysclk_freq = 80E6; + * @endcode + * + * The same can be achieved by a simple call to high-level routines: + * @code + * // A divisor of 5 gives us a clock of 400/5 = 80MHz + * #define PLLDIV_80MHZ 5 + * + * rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLLDIV_80MHZ); + * @endcode + * + * @{ + */ + +#include + +/** + * @defgroup rcc_low_level Low-level clock control API +@ingroup rcc_file + * @{ + */ +/** + * \brief System clock frequency + * + * This variable is provided to keep track of the system clock frequency. It + * should be updated every time the system clock is changed via the fine-grained + * mechanisms. The initial value is 16MHz, which corresponds to the clock of the + * internal 16MHz oscillator. + * + * High-level routines update the system clock automatically. + * For read access, it is recommended to acces this variable via + * @code + * rcc_get_system_clock_frequency(); + * @endcode + * + * If write access is desired (i.e. when changing the system clock via the + * fine-grained mechanisms), then include the following line in your code: + * @code + * extern uint32_t lm4f_rcc_sysclk_freq; + * @endcode + */ +uint32_t lm4f_rcc_sysclk_freq = 16000000; + + +/** + * \brief Configure the crystal type connected to the device. + * + * Configure the crystal type connected between the OSCO and OSCI pins by + * writing the appropriate value to the XTAL field in SYSCTL_RCC. The PLL + * parameters are automatically adjusted in hardware to provide a PLL clock of + * 400MHz. + * + * @param[in] xtal predefined crystal type @see xtal_t + */ +void rcc_configure_xtal(enum xtal_t xtal) +{ + uint32_t reg32; + + reg32 = SYSCTL_RCC; + reg32 &= ~SYSCTL_RCC_XTAL_MASK; + reg32 |= (xtal & SYSCTL_RCC_XTAL_MASK); + SYSCTL_RCC = reg32; +} + +/** + * \brief Disable the main oscillator + * + * Sets the IOSCDIS bit in SYSCTL_RCC, disabling the main oscillator. + */ +void rcc_disable_main_osc(void) +{ + SYSCTL_RCC |= SYSCTL_RCC_MOSCDIS; +} + +/** + * \brief Disable the internal oscillator + * + * Sets the IOSCDIS bit in SYSCTL_RCC, disabling the internal oscillator. + */ +void rcc_disable_interal_osc(void) +{ + SYSCTL_RCC |= SYSCTL_RCC_IOSCDIS; +} + +/** + * \brief Enable the main oscillator + * + * Clears the MOSCDIS bit in SYSCTL_RCC, enabling the main oscillator. + */ +void rcc_enable_main_osc(void) +{ + SYSCTL_RCC &= ~SYSCTL_RCC_MOSCDIS; +} + +/** + * \brief Enable the internal oscillator + * + * Clears the IOSCDIS bit in SYSCTL_RCC, enabling the internal oscillator. + */ +void rcc_enable_interal_osc(void) +{ + SYSCTL_RCC &= ~SYSCTL_RCC_IOSCDIS; +} + +/** + * \brief Enable the use of SYSCTL_RCC2 register for clock control + * + * Enables the USERCC2 bit in SYSCTTL_RCC2. Settings in SYSCTL_RCC2 will + * override settings in SYSCTL_RCC. + * This function must be called before other calls to manipulate the clock, as + * libopencm3 uses the SYSCTL_RCC2 register. + */ +void rcc_enable_rcc2(void) +{ + SYSCTL_RCC2 |= SYSCTL_RCC2_USERCC2; +} + +/** + * \brief Power down the main PLL + * + * Sets the SYSCTL_RCC2_PWRDN2 in SYSCTL_RCC2 to power down the PLL. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_pll_off(void) +{ + SYSCTL_RCC2 |= SYSCTL_RCC2_PWRDN2; +} + +/** + * \brief Power up the main PLL + * + * Clears the PWRDN2 in SYSCTL_RCC2 to power on the PLL. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_pll_on(void) +{ + SYSCTL_RCC2 &= ~SYSCTL_RCC2_PWRDN2; +} + +/** + * \brief Set the oscillator source to be used by the system clock + * + * Set the clock source for the system clock. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_set_osc_source(enum osc_src src) +{ + uint32_t reg32; + + reg32 = SYSCTL_RCC2; + reg32 &= ~SYSCTL_RCC2_OSCSRC2_MASK; + reg32 |= (src & SYSCTL_RCC2_OSCSRC2_MASK); + SYSCTL_RCC2 = reg32; +} + +/** + * \brief Disable the PLL bypass and use the PLL clock + * + * Clear BYPASS2 in SYSCTL_RCC2. The system clock is derived from the PLL + * clock divided by the divisor specified in SYSDIV2. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_pll_bypass_disable(void) +{ + SYSCTL_RCC2 &= ~SYSCTL_RCC2_BYPASS2; +} + +/** + * \brief Enable the PLL bypass and use the oscillator clock + * + * Set BYPASS2 in SYSCTL_RCC2. The system clock is derived from the oscillator + * clock divided by the divisor specified in SYSDIV2. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_pll_bypass_enable(void) +{ + SYSCTL_RCC2 |= SYSCTL_RCC2_BYPASS2; +} + +/** + * \brief Set the PLL clock divisor (from 400MHz) + * + * Set the binary divisor used to predivide the system clock down for use as the + * timing reference for the PWM module. The divisor is expected to be a divisor + * from 400MHz, not 200MHz. The DIV400 is also set. + * + * Specifies the divisor that used to generate the system clock from either the + * PLL output or the oscillator source (depending on the BYPASS2 bit in + * SYSCTL_RCC2). SYSDIV2 is used for the divisor when both the USESYSDIV bit in + * SYSCTL_RCC is set. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + * + * @param[in] div clock divisor to apply to the 400MHz PLL clock. It is the + * caller's responsibility to ensure that the divisor will not create + * a system clock that is out of spec. + */ +void rcc_set_pll_divisor(uint8_t div400) +{ + uint32_t reg32; + + SYSCTL_RCC |= SYSCTL_RCC_USESYSDIV; + + reg32 = SYSCTL_RCC2; + reg32 &= ~SYSCTL_RCC2_SYSDIV400_MASK; + reg32 |= ((div400 - 1) << 22) & SYSCTL_RCC2_SYSDIV400_MASK; + /* We are expecting a divider from 400MHz */ + reg32 |= SYSCTL_RCC2_DIV400; + SYSCTL_RCC2 = reg32; +} +/** + * \brief Set the PWM unit clock divisor + * + * Set the binary divisor used to predivide the system clock down for use as the + * timing reference for the PWM module. + * + * @param[in] div clock divisor to use @see pwm_clkdiv_t + */ +void rcc_set_pwm_divisor(enum pwm_clkdiv div) +{ + uint32_t reg32; + + reg32 = SYSCTL_RCC; + reg32 &= ~SYSCTL_RCC_PWMDIV_MASK; + reg32 |= (div & SYSCTL_RCC_PWMDIV_MASK); + SYSCTL_RCC = reg32; +} + +/** + * \brief Power down the USB PLL + * + * Sets the USBPWRDN in SYSCTL_RCC2 to power down the USB PLL. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_usb_pll_off(void) +{ + SYSCTL_RCC2 |= SYSCTL_RCC2_USBPWRDN; +} + +/** + * \brief Power up the USB PLL + * + * Clears the USBPWRDN in SYSCTL_RCC2 to power on the USB PLL. + * + * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this + * function. + */ +void rcc_usb_pll_on(void) +{ + SYSCTL_RCC2 &= ~SYSCTL_RCC2_USBPWRDN; +} + +/** + * \brief Wait for main PLL to lock + * + * Waits until the LOCK bit in SYSCTL_PLLSTAT is set. This guarantees that the + * PLL is locked, and ready to use. + */ +void rcc_wait_for_pll_ready(void) +{ + while (!(SYSCTL_PLLSTAT & SYSCTL_PLLSTAT_LOCK)); +} + +/** + * @} + */ + +/** + * @defgroup rcc_high_level High-level clock control API +@ingroup rcc_file + * @{ + */ + +/** + * \brief Change the PLL divisor + * + * Changes the divisor applied to the 400MHz PLL clock. The PLL must have + * previously been configured by selecting an appropriate XTAL value, and + * turning on the PLL. This function does not reconfigure the XTAL value or + * oscillator source. It only changes the PLL divisor. + * + * The PLL is bypassed before modifying the divisor, and the function blocks + * until the PLL is locked, then the bypass is disabled, before returning. + * + * @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock. + */ +void rcc_change_pll_divisor(uint8_t pll_div400) +{ + /* Bypass the PLL while its settings are modified */ + rcc_pll_bypass_enable(); + /* Change the clock divisor */ + rcc_set_pll_divisor(pll_div400); + /* We cannot use the PLL as a clock source until it locks */ + rcc_wait_for_pll_ready(); + /* Disable PLL bypass to derive the system clock from the PLL clock */ + rcc_pll_bypass_disable(); + /* Update the system clock frequency for housekeeping */ + lm4f_rcc_sysclk_freq = (uint32_t)400E6 / pll_div400; +} + +/** + * \brief Get the system clock frequency + * + * @return System clock frequency in Hz + */ +uint32_t rcc_get_system_clock_frequency(void) +{ + return lm4f_rcc_sysclk_freq; +} + +/* Get the clock frequency corresponding to a given XTAL value */ +static uint32_t xtal_to_freq(enum xtal_t xtal) +{ + const uint32_t freqs[] = { + 4000000, /* XTAL_4M */ + 4096000, /* XTAL_4M_096 */ + 4915200, /* XTAL_4M_9152 */ + 5000000, /* ,XTAL_5M */ + 5120000, /* XTAL_5M_12 */ + 6000000, /* XTAL_6M */ + 6144000, /* XTAL_6M_144 */ + 7372800, /* XTAL_7M_3728 */ + 8000000, /* XTAL_8M */ + 8192000, /* XTAL_8M_192 */ + 10000000, /* XTAL_10M */ + 12000000, /* XTAL_12M */ + 12288000, /* XTAL_12M_288 */ + 13560000, /* XTAL_13M_56 */ + 14318180, /* XTAL_14M_31818 */ + 16000000, /* XTAL_16M */ + 16384000, /* XTAL_16M_384 */ + 18000000, /* XTAL_18M */ + 20000000, /* XTAL_20M */ + 24000000, /* XTAL_24M */ + 25000000, /* XTAL_25M */ + }; + + return freqs[xtal - XTAL_4M]; +} + +/** + * \brief Configure the system clock source + * + * Sets up the system clock, including configuring the oscillator source, and + * PLL to acheve the desired system clock frequency. Where applicable, The LM4F + * clock API uses the new RCC2 register to configure clock parameters. + * + * Enables the main oscillator if the clock source is OSCSRC_MOSC. If the main + * oscillator was previously enabled, it will not be disabled. If desired, it + * can be separately disabled by a call to rcc_disable_main_osc(). + * + * Configures the system clock to run from the 400MHz PLL with a divisor of + * pll_div400 applied. If pll_div400 is 0, then the PLL is disabled, and the + * system clock is configured to run off a "raw" clock. If the PLL was + * previously powered on, it will not be disabled. If desired, it can de powered + * off by a call to rcc_pll_off(). + * + * @param [in] osc_src Oscillator from where to derive the system clock. + * @param [in] xtal Type of crystal connected to the OSCO/OSCI pins + * @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock. + * If 0, then the PLL is disabled, and the system runs + * off a "raw" clock. + * + * @return System clock frequency in Hz + */ +void rcc_sysclk_config(enum osc_src src, enum xtal_t xtal, uint8_t pll_div400) +{ + /* + * We could be using the PLL at this point, or we could be running of a + * raw clock. Either way, it is safer to bypass the PLL now. + */ + rcc_pll_bypass_enable(); + + /* Enable the main oscillator, if needed */ + if (src == OSCSRC_MOSC) { + rcc_enable_main_osc(); + } + + /* Make RCC2 override RCC */ + rcc_enable_rcc2(); + + /* Set XTAL value to 16MHz */ + rcc_configure_xtal(xtal); + /* Set the oscillator source */ + rcc_set_osc_source(src); + if (pll_div400) { + /* Enable the PLL */ + rcc_pll_on(); + /* Configure the PLL to the divisor we want */ + rcc_change_pll_divisor(pll_div400); + } else { + /* We are running off a raw clock */ + switch (src) { + case OSCSRC_PIOSC: + lm4f_rcc_sysclk_freq = 16000000; + break; + case OSCSRC_PIOSC_D4: + lm4f_rcc_sysclk_freq = 4000000; + break; + case OSCSRC_MOSC: + lm4f_rcc_sysclk_freq = xtal_to_freq(xtal); + break; + case OSCSRC_32K_EXT: + lm4f_rcc_sysclk_freq = 32768; + break; + case OSCSRC_30K_INT: /* Fall through. */ + default: + /* + * We either are running off the internal 30KHz + * oscillator, which is +- 50% imprecise, or we got a + * bad osc_src parameter. + */ + lm4f_rcc_sysclk_freq = 0; + } + } + +} + +/** + * @} + * @} + */ diff --git a/libopencm3/lib/lm4f/systemcontrol.c b/libopencm3/lib/lm4f/systemcontrol.c new file mode 100644 index 0000000..c2993b9 --- /dev/null +++ b/libopencm3/lib/lm4f/systemcontrol.c @@ -0,0 +1,40 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/** + * \brief Enable the clock source for the peripheral + * + * @param[in] periph peripheral and clock type to enable @see lm4f_clken + */ +void periph_clock_enable(enum lm4f_clken periph) +{ + MMIO32(SYSCTL_BASE + (periph >> 5)) |= 1 << (periph & 0x1f); +} + +/** + * \brief Disable the clock source for the peripheral + * + * @param[in] periph peripheral and clock type to enable @see lm4f_clken + */ +void periph_clock_disable(enum lm4f_clken periph) +{ + MMIO32(SYSCTL_BASE + (periph >> 5)) &= ~(1 << (periph & 0x1f)); +} diff --git a/libopencm3/lib/lm4f/uart.c b/libopencm3/lib/lm4f/uart.c new file mode 100644 index 0000000..c5e3e04 --- /dev/null +++ b/libopencm3/lib/lm4f/uart.c @@ -0,0 +1,627 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/** + * @defgroup uart_file UART + * + * @ingroup LM4Fxx + * + * @author @htmlonly © @endhtmlonly 2013 Alexandru Gagniuc + * + * \brief libopencm3 LM4F Universal Asynchronous Receiver Transmitter + * + * The LM4F UART API provides functionality for accessing the UART hardware of + * the LM4F. + * + * Please see the individual UART modules for more details. To use the UART, the + * uart.h header needs to be included: + * @code{.c} + * #include + * @endcode + * + * @{ + */ + +#include +#include +#include + +/** @defgroup uart_config UART configuration + * @ingroup uart_file + * + * \brief Enabling and configuring the UART + * + * Enabling the UART is a two step process. The GPIO on which the UART resides + * must be enabled, and the UART pins must be configured as alternate function, + * digital pins. Pins must also be muxed to the appropriate alternate function. + * This is done with the GPIO API. + * + * The second step involves enabling and the UART itself. The UART should be + * disabled while it is being configured. + * -# The UART clock must be enabled with @ref periph_clock_enable(). + * -# The UART must be disabled with @ref uart_disable(). + * -# The UART clock source should be chosen before setting the baudrate. + * -# Baudrate, data bits, stop bit length, and parity can be configured. + * -# If needed, enable CTS or RTS lines via the @ref uart_set_flow_control(). + * -# The UART can now be enabled with @ref uart_enable(). + * + * For example, to enable UART1 at 115200 8n1 with hardware flow control: + * @code{.c} + * // Enable the UART clock + * periph_clock_enable(RCC_UART1); + * // We need a brief delay before we can access UART config registers + * __asm__("nop"); __asm__("nop"); __asm__("nop"); + * // Disable the UART while we mess with its settings + * uart_disable(UART1); + * // Configure the UART clock source as precision internal oscillator + * uart_clock_from_piosc(); + * // Set communication parameters + * uart_set_baudrate(UART1, 115200); + * uart_set_databits(UART1, 8); + * uart_set_parity(UART1, UART_PARITY_NONE); + * uart_set_stopbits(UART1, 1); + * // Enable RTC and CTS lines + * uart_set_flow_control(UART1, UART_FLOWCTL_HARD_RTS_CTS); + * // Now that we're done messing with the settings, enable the UART + * uart_enable(UART1); + * @endcode + */ +/**@{*/ +/** + * \brief Enable the UART + * + * Enable the UART. The Rx and Tx lines are also enabled. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable(uint32_t uart) +{ + UART_CTL(uart) |= (UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE); +} + +/** + * \brief Disable the UART + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable(uint32_t uart) +{ + UART_CTL(uart) &= ~UART_CTL_UARTEN; +} + +/** + * \brief Set UART baudrate + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] baud Baud rate in bits per second (bps).* + */ +void uart_set_baudrate(uint32_t uart, uint32_t baud) +{ + uint32_t clock; + + /* Are we running off the internal clock or system clock? */ + if (UART_CC(uart) == UART_CC_CS_PIOSC) { + clock = 16000000; + } else { + clock = rcc_get_system_clock_frequency(); + } + + /* Find the baudrate divisor */ + uint32_t div = (((clock * 8) / baud) + 1) / 2; + + /* Set the baudrate divisors */ + UART_IBRD(uart) = div / 64; + UART_FBRD(uart) = div % 64; +} + +/** + * \brief Set UART databits + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] databits number of data bits per transmission. + */ +void uart_set_databits(uint32_t uart, uint8_t databits) +{ + uint32_t reg32, bitint32_t; + + /* This has the same effect as using UART_LCRH_WLEN_5/6/7/8 directly */ + bitint32_t = (databits - 5) << 5; + + /* TODO: What about 9 data bits? */ + + reg32 = UART_LCRH(uart); + reg32 &= ~UART_LCRH_WLEN_MASK; + reg32 |= bitint32_t; + UART_LCRH(uart) = reg32; +} + +/** + * \brief Set UART stopbits + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] bits the requested number of stopbits, either 1 or 2. + */ +void uart_set_stopbits(uint32_t uart, uint8_t stopbits) +{ + if (stopbits == 2) { + UART_LCRH(uart) |= UART_LCRH_STP2; + } else { + UART_LCRH(uart) &= ~UART_LCRH_STP2; + } +} + +/** + * \brief Set UART parity + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] bits the requested parity scheme. + */ +void uart_set_parity(uint32_t uart, enum uart_parity parity) +{ + uint32_t reg32; + + reg32 = UART_LCRH(uart); + reg32 |= UART_LCRH_PEN; + reg32 &= ~(UART_LCRH_SPS | UART_LCRH_EPS); + + switch (parity) { + case UART_PARITY_NONE: + /* Once we disable parity the other bits are meaningless */ + UART_LCRH(uart) &= ~UART_LCRH_PEN; + return; + case UART_PARITY_ODD: + break; + case UART_PARITY_EVEN: + reg32 |= UART_LCRH_EPS; + break; + case UART_PARITY_STICK_0: + reg32 |= (UART_LCRH_SPS | UART_LCRH_EPS); + break; + case UART_PARITY_STICK_1: + reg32 |= UART_LCRH_SPS; + break; + } + + UART_LCRH(uart) = reg32; +} + +/** + * \brief Set the flow control scheme + * + * Set the flow control scheme by enabling or disabling RTS and CTS lines. This + * will only have effect if the given UART supports the RTS and CTS lines. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] flow The flow control scheme to use (none, RTS, CTS or both) \n + * UART_FLOWCTL_RTS -- enable the RTS line \n + * UART_FLOWCTL_CTS -- enable the CTS line \n + * UART_FLOWCTL_RTS_CTS -- enable both RTS and CTS lines + */ +void uart_set_flow_control(uint32_t uart, enum uart_flowctl flow) +{ + uint32_t reg32 = UART_CTL(uart); + + reg32 &= ~(UART_CTL_RTSEN | UART_CTL_CTSEN); + + if (flow == UART_FLOWCTL_RTS) { + reg32 |= UART_CTL_RTSEN; + } else if (flow == UART_FLOWCTL_CTS) { + reg32 |= UART_CTL_CTSEN; + } else if (flow == UART_FLOWCTL_RTS_CTS) { + reg32 |= (UART_CTL_RTSEN | UART_CTL_CTSEN); + } + + UART_CTL(uart) = reg32; +} + +/** + * \brief Clock the UART module from the internal oscillator + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_clock_from_piosc(uint32_t uart) +{ + UART_CC(uart) = UART_CC_CS_PIOSC; +} + +/** + * \brief Clock the UART module from the system clock + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_clock_from_sysclk(uint32_t uart) +{ + UART_CC(uart) = UART_CC_CS_SYSCLK; +} +/**@}*/ + +/** @defgroup uart_send_recv UART transmission and reception + * @ingroup uart_file + * + * \brief Sending and receiving data through the UART + * + * Primitives for sending and recieving data are provided, @ref uart_send() and + * @ref uart_recv(). These primitives do not check if data can be transmitted + * or wait for data. If waiting until data is available or can be transmitted is + * desired, blocking primitives are also available, @ref uart_send_blocking() + * and @ref uart_recv_blocking(). + * + * These primitives only handle one byte at at time, and thus may be unsuited + * for some applications. You may also consider using @ref uart_dma. + */ +/**@{*/ +/** + * \brief UART Send a Data Word. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] data data to send. + */ +void uart_send(uint32_t uart, uint16_t data) +{ + data &= 0xFF; + UART_DR(uart) = data; +} + +/** + * \brief UART Read a Received Data Word. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @return data from the Rx FIFO. + */ +uint16_t uart_recv(uint32_t uart) +{ + return UART_DR(uart) & UART_DR_DATA_MASK; +} + +/** + * \brief UART Wait for Transmit Data Buffer Not Full + * + * Blocks until the transmit data FIFO is not empty and can accept the next data + * word. + * \n + * Even if the FIFO is not empty, this function will return as long as there is + * room for at least one more word. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_wait_send_ready(uint32_t uart) +{ + /* Wait until the Tx FIFO is no longer full */ + while (UART_FR(uart) & UART_FR_TXFF); +} + +/** + * \brief UART Wait for Received Data Available + * + * Blocks until the receive data FIFO holds a at least valid received data word. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_wait_recv_ready(uint32_t uart) +{ + /* Wait until the Tx FIFO is no longer empty */ + while (UART_FR(uart) & UART_FR_RXFE); +} + +/** + * \brief UART Send Data Word with Blocking + * + * Blocks until the transmit data FIFO can accept the next data word for + * transmission. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_send_blocking(uint32_t uart, uint16_t data) +{ + uart_wait_send_ready(uart); + uart_send(uart, data); +} + +/** + * \brief UART Read a Received Data Word with Blocking. + * + * Wait until a data word has been received then return the word. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @return data from the Rx FIFO. + */ +uint16_t uart_recv_blocking(uint32_t uart) +{ + uart_wait_recv_ready(uart); + return uart_recv(uart); +} +/**@}*/ + +/** @defgroup uart_irq UART Interrupt control + * @ingroup uart_file + * + * \brief Configuring interrupts from the UART + * + * To have an event generate an interrupt, its interrupt source must be + * unmasked. This can be achieved with @ref uart_enable_interrupts(). Interrupts + * which are no longer needed can be disabled through + * @ref uart_disable_interrupts(). + * + * In order for the interrupt to generate an IRQ and a call to the interrupt + * service routine, the interrupt for the target UART must be routed through the + * NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is + * needed: + * @code{.c} + * #include + * @endcode + * + * Enabling an interrupt is as simple as unmasking the desired interrupt, and + * routing the desired UART's interrupt through the NVIC. + * @code{.c} + * // Unmask receive interrupt + * uart_enable_rx_interrupt(UART0); + * // Make sure the interrupt is routed through the NVIC + * nvic_enable_irq(NVIC_UART0_IRQ); + * @endcode + * + * If a more than one interrupt is to be enabled at one time, the interrupts + * can be enabled by a single call to @ref uart_enable_interrupts(). + * For example: + * @code{.c} + * // Unmask receive, CTS, and RI, interrupts + * uart_enable_interrupts(UART0, UART_INT_RX | UART_INT_RI | UART_INT_CTS); + * @endcode + * + * After interrupts are properly enabled and routed through the NVIC, when an + * event occurs, the appropriate IRQ flag is set by hardware, and execution + * jumps to the UART ISR. The ISR should query the IRQ flags to determine which + * event caused the interrupt. For this, use @ref uart_is_interrupt_source(), + * with the desired UART_INT flag. After one or more interrupt sources are + * serviced, the IRQ flags must be cleared by the ISR. This can be done with + * @ref uart_clear_interrupt_flag(). + * + * A typical UART ISR may look like the following: + * @code{.c} + * void uart0_isr(void) + * { + * uint32_t serviced_irqs = 0; + * + * // Process individual IRQs + * if (uart_is_interrupt_source(UART0, UART_INT_RX)) { + * process_rx_event(); + * serviced_irq |= UART_INT_RX; + * } + * if (uart_is_interrupt_source(UART0, UART_INT_CTS)) { + * process_cts_event(); + * serviced_irq |= UART_INT_CTS; + * } + * + * // Clear the interupt flag for the processed IRQs + * uart_clear_interrupt_flag(UART0, serviced_irqs); + * } + * @endcode + */ +/**@{*/ +/** + * \brief Enable Specific UART Interrupts + * + * Enable any combination of interrupts. Interrupts may be OR'ed together to + * enable them with one call. For example, to enable both the RX and CTS + * interrupts, pass (UART_INT_RX | UART_INT_CTS) + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] ints Interrupts which to enable. Any combination of interrupts may + * be specified by OR'ing then together + */ +void uart_enable_interrupts(uint32_t uart, enum uart_interrupt_flag ints) +{ + UART_IM(uart) |= ints; +} + +/** + * \brief Enable Specific UART Interrupts + * + * Disabe any combination of interrupts. Interrupts may be OR'ed together to + * disable them with one call. For example, to disable both the RX and CTS + * interrupts, pass (UART_INT_RX | UART_INT_CTS) + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] ints Interrupts which to disable. Any combination of interrupts + * may be specified by OR'ing then together + */ +void uart_disable_interrupts(uint32_t uart, enum uart_interrupt_flag ints) +{ + UART_IM(uart) &= ~ints; +} + +/** + * \brief Enable the UART Receive Interrupt. + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable_rx_interrupt(uint32_t uart) +{ + uart_enable_interrupts(uart, UART_INT_RX); +} + +/** + * \brief Disable the UART Receive Interrupt. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable_rx_interrupt(uint32_t uart) +{ + uart_disable_interrupts(uart, UART_INT_RX); +} + +/** + * \brief Enable the UART Transmit Interrupt. + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable_tx_interrupt(uint32_t uart) +{ + uart_enable_interrupts(uart, UART_INT_TX); +} + +/** + * \brief Disable the UART Transmit Interrupt. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable_tx_interrupt(uint32_t uart) +{ + uart_disable_interrupts(uart, UART_INT_TX); +} + +/** + * \brief Mark interrupt as serviced + * + * After an interrupt is services, its flag must be cleared. If the flag is not + * cleared, then execution will jump back to the start of the ISR after the ISR + * returns. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] ints Interrupts which to clear. Any combination of interrupts may + * be specified by OR'ing then together + */ +void uart_clear_interrupt_flag(uint32_t uart, enum uart_interrupt_flag ints) +{ + UART_ICR(uart) |= ints; +} +/**@}*/ + +/** @defgroup uart_dma UART DMA control + * @ingroup uart_file + * + * \brief Enabling Direct Memory Access transfers for the UART + * + */ +/**@{*/ + +/** + * \brief Enable the UART Receive DMA. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable_rx_dma(uint32_t uart) +{ + UART_DMACTL(uart) |= UART_DMACTL_RXDMAE; +} + +/** + * \brief Disable the UART Receive DMA. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable_rx_dma(uint32_t uart) +{ + UART_DMACTL(uart) &= ~UART_DMACTL_RXDMAE; +} + +/** + * \brief Enable the UART Transmit DMA. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable_tx_dma(uint32_t uart) +{ + UART_DMACTL(uart) |= UART_DMACTL_TXDMAE; +} + +/** + * \brief Disable the UART Transmit DMA. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable_tx_dma(uint32_t uart) +{ + UART_DMACTL(uart) &= ~UART_DMACTL_TXDMAE; +} +/**@}*/ + +/** @defgroup uart_fifo UART FIFO control + * @ingroup uart_file + * + * \brief Enabling and controlling UART FIFO + * + * The UART on the LM4F can either be used with a single character TX and RX + * buffer, or with a 8 character TX and RX FIFO. In order to use the FIFO it + * must be enabled, this is done with uart_enable_fifo() and can be disabled + * again with uart_disable_fifo(). On reset the FIFO is disabled, and it must + * be explicitly be enabled. + * + * When enabling the UART FIFOs, RX and TX interrupts are triggered according + * to the amount of data in the FIFOs. For the RX FIFO the trigger level is + * defined by how full the FIFO is. The TX FIFO trigger level is defined by + * how empty the FIFO is instead. + * + * For example, to enable the FIFOs and trigger interrupts for a single + * received and single transmitted character: + * @code{.c} + * uart_enable_fifo(UART0); + * uart_set_fifo_trigger_levels(UART0, UART_FIFO_RX_TRIG_1_8, + * UART_FIFO_TX_TRIG_7_8); + * @endcode + */ +/**@{*/ + +/** + * \brief Enable FIFO for the UART. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_enable_fifo(uint32_t uart) +{ + UART_LCRH(uart) |= UART_LCRH_FEN; +} + +/** + * \brief Disable FIFO for the UART. + * + * @param[in] uart UART block register address base @ref uart_reg_base + */ +void uart_disable_fifo(uint32_t uart) +{ + UART_LCRH(uart) &= ~UART_LCRH_FEN; +} + +/** + * \brief Set the FIFO trigger levels. + * + * @param[in] uart UART block register address base @ref uart_reg_base + * @param[in] rx_level Trigger level for RX FIFO + * @param[in] tx_level Trigger level for TX FIFO + */ +void uart_set_fifo_trigger_levels(uint32_t uart, + enum uart_fifo_rx_trigger_level rx_level, + enum uart_fifo_tx_trigger_level tx_level) +{ + UART_IFLS(uart) = rx_level | tx_level; +} +/**@}*/ + + +/** + * @} + */ diff --git a/libopencm3/lib/lm4f/usb_lm4f.c b/libopencm3/lib/lm4f/usb_lm4f.c new file mode 100644 index 0000000..e70e604 --- /dev/null +++ b/libopencm3/lib/lm4f/usb_lm4f.c @@ -0,0 +1,651 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Alexandru Gagniuc + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/** + * @defgroup usb_file USB + * + * @ingroup LM4Fxx + * + * @author @htmlonly © @endhtmlonly 2013 + * Alexandru Gagniuc + * + * \brief libopencm3 LM4F Universal Serial Bus controller + * + * The LM4F USB driver is integrated with the libopencm3 USB stack. You should + * use the generic stack. + * + * To use this driver, tell the linker to look for it: + * @code{.c} + * extern usbd_driver lm4f_usb_driver; + * @endcode + * + * And pass this driver as an argument when initializing the USB stack: + * @code{.c} + * usbd_device *usbd_dev; + * usbd_dev = usbd_init(&lm4f_usb_driver, ...); + * @endcode + * + * Polling or interrupt-driven? + * + * The LM4F USB driver will work fine regardless of whether it is called from an + * interrupt service routine, or from the main program loop. + * + * Polling USB from the main loop requires calling @ref usbd_poll() from the + * main program loop. + * For example: + * @code{.c} + * // Main program loop + * while(1) { + * usbd_poll(usb_dev); + * do_other_stuff(); + * ... + * @endcode + * + * Running @ref usbd_poll() from an interrupt has the advantage that it is only + * called when needed, saving CPU cycles for the main program. + * + * RESET, DISCON, RESUME, and SUSPEND interrupts must be enabled, along with the + * interrupts for any endpoint that is used. The EP0_TX interrupt must be + * enabled for the control endpoint to function correctly. + * For example, if EP1IN and EP2OUT are used, then the EP0_TX, EP1_TX, and + * EP2_RX interrupts should be enabled: + * @code{.c} + * // Enable USB interrupts for EP0, EP1IN, and EP2OUT + * ints = USB_INT_RESET | USB_INT_DISCON | USB_INT_RESUME | + * USB_INT_SUSPEND; + * usb_enable_interrupts(ints, USB_EP2_INT, USB_EP0_INT | USB_EP1_INT); + * // Route the interrupts through the NVIC + * nvic_enable_irq(NVIC_USB0_IRQ); + * @endcode + * + * The USB ISR only has to call @ref usbd_poll(). + * + * @code{.c} + * void usb0_isr(void) + * { + * usbd_poll(usb_dev); + * } + * @endcode + * @{ + */ + +/* + * TODO list: + * + * 1) Driver works by reading and writing to the FIFOs one byte at a time. It + * has no knowledge of DMA. + * 2) Double-buffering is supported. How can we take advantage of it to speed + * up endpoint transfers. + * 3) No benchmarks as to the endpoint's performance has been done. + */ +/* + * The following are resources referenced in comments: + * [1] http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/238784.aspx + */ + +#include +#include +#include +#include +#include "../../lib/usb/usb_private.h" + +#include + + +#define MAX_FIFO_RAM (4 * 1024) + +const struct _usbd_driver lm4f_usb_driver; + +/** + * \brief Enable Specific USB Interrupts + * + * Enable any combination of interrupts. Interrupts may be OR'ed together to + * enable them with one call. For example, to enable both the RESUME and RESET + * interrupts, pass (USB_INT_RESUME | USB_INT_RESET) + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] ints Interrupts which to enable. Any combination of interrupts may + * be specified by OR'ing then together + * @param[in] rx_ints Endpoints for which to generate an interrupt when a packet + * packet is received. + * @param[in] tx_ints Endpoints for which to generate an interrupt when a packet + * packet is finished transmitting. + */ +void usb_enable_interrupts(enum usb_interrupt ints, + enum usb_ep_interrupt rx_ints, + enum usb_ep_interrupt tx_ints) +{ + USB_IE |= ints; + USB_RXIE |= rx_ints; + USB_TXIE |= tx_ints; +} + +/** + * \brief Disable Specific USB Interrupts + * + * Disable any combination of interrupts. Interrupts may be OR'ed together to + * enable them with one call. For example, to disable both the RESUME and RESET + * interrupts, pass (USB_INT_RESUME | USB_INT_RESET) + * + * Note that the NVIC must be enabled and properly configured for the interrupt + * to be routed to the CPU. + * + * @param[in] ints Interrupts which to disable. Any combination of interrupts + * may be specified by OR'ing then together + * @param[in] rx_ints Endpoints for which to stop generating an interrupt when a + * packet packet is received. + * @param[in] tx_ints Endpoints for which to stop generating an interrupt when a + * packet packet is finished transmitting. + */ +void usb_disable_interrupts(enum usb_interrupt ints, + enum usb_ep_interrupt rx_ints, + enum usb_ep_interrupt tx_ints) +{ + USB_IE &= ~ints; + USB_RXIE &= ~rx_ints; + USB_TXIE &= ~tx_ints; +} + +/** + * @cond private + */ +static inline void lm4f_usb_soft_disconnect(void) +{ + USB_POWER &= ~USB_POWER_SOFTCONN; +} + +static inline void lm4f_usb_soft_connect(void) +{ + USB_POWER |= USB_POWER_SOFTCONN; +} + +static void lm4f_set_address(usbd_device *usbd_dev, uint8_t addr) +{ + (void)usbd_dev; + + USB_FADDR = addr & USB_FADDR_FUNCADDR_MASK; +} + +static void lm4f_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*callback) (usbd_device *usbd_dev, uint8_t ep)) +{ + (void)usbd_dev; + (void)type; + + uint8_t reg8; + uint16_t fifo_size; + + const bool dir_tx = addr & 0x80; + const uint8_t ep = addr & 0x0f; + + /* + * We do not mess with the maximum packet size, but we can only allocate + * the FIFO in power-of-two increments. + */ + if (max_size > 1024) { + fifo_size = 2048; + reg8 = USB_FIFOSZ_SIZE_2048; + } else if (max_size > 512) { + fifo_size = 1024; + reg8 = USB_FIFOSZ_SIZE_1024; + } else if (max_size > 256) { + fifo_size = 512; + reg8 = USB_FIFOSZ_SIZE_512; + } else if (max_size > 128) { + fifo_size = 256; + reg8 = USB_FIFOSZ_SIZE_256; + } else if (max_size > 64) { + fifo_size = 128; + reg8 = USB_FIFOSZ_SIZE_128; + } else if (max_size > 32) { + fifo_size = 64; + reg8 = USB_FIFOSZ_SIZE_64; + } else if (max_size > 16) { + fifo_size = 32; + reg8 = USB_FIFOSZ_SIZE_32; + } else if (max_size > 8) { + fifo_size = 16; + reg8 = USB_FIFOSZ_SIZE_16; + } else { + fifo_size = 8; + reg8 = USB_FIFOSZ_SIZE_8; + } + + /* Endpoint 0 is more special */ + if (addr == 0) { + USB_EPIDX = 0; + + if (reg8 > USB_FIFOSZ_SIZE_64) { + reg8 = USB_FIFOSZ_SIZE_64; + } + + /* The RX and TX FIFOs are shared for EP0 */ + USB_RXFIFOSZ = reg8; + USB_TXFIFOSZ = reg8; + + /* + * Regardless of how much we allocate, the first 64 bytes + * are always reserved for EP0. + */ + usbd_dev->fifo_mem_top_ep0 = 64; + return; + } + + /* Are we out of FIFO space? */ + if (usbd_dev->fifo_mem_top + fifo_size > MAX_FIFO_RAM) { + return; + } + + USB_EPIDX = addr & USB_EPIDX_MASK; + + /* FIXME: What about double buffering? */ + if (dir_tx) { + USB_TXMAXP(ep) = max_size; + USB_TXFIFOSZ = reg8; + USB_TXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3); + if (callback) { + usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_IN] = + (void *)callback; + } + if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) { + USB_TXCSRH(ep) |= USB_TXCSRH_ISO; + } else { + USB_TXCSRH(ep) &= ~USB_TXCSRH_ISO; + } + } else { + USB_RXMAXP(ep) = max_size; + USB_RXFIFOSZ = reg8; + USB_RXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3); + if (callback) { + usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_OUT] = + (void *)callback; + } + if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) { + USB_RXCSRH(ep) |= USB_RXCSRH_ISO; + } else { + USB_RXCSRH(ep) &= ~USB_RXCSRH_ISO; + } + } + + usbd_dev->fifo_mem_top += fifo_size; +} + +static void lm4f_endpoints_reset(usbd_device *usbd_dev) +{ + /* + * The core resets the endpoints automatically on reset. + * The first 64 bytes are always reserved for EP0 + */ + usbd_dev->fifo_mem_top = 64; +} + +static void lm4f_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, + uint8_t stall) +{ + (void)usbd_dev; + + const uint8_t ep = addr & 0x0f; + const bool dir_tx = addr & 0x80; + + if (ep == 0) { + if (stall) { + USB_CSRL0 |= USB_CSRL0_STALL; + } else { + USB_CSRL0 &= ~USB_CSRL0_STALL; + } + return; + } + + if (dir_tx) { + if (stall) { + (USB_TXCSRL(ep)) |= USB_TXCSRL_STALL; + } else { + (USB_TXCSRL(ep)) &= ~USB_TXCSRL_STALL; + } + } else { + if (stall) { + (USB_RXCSRL(ep)) |= USB_RXCSRL_STALL; + } else { + (USB_RXCSRL(ep)) &= ~USB_RXCSRL_STALL; + } + } +} + +static uint8_t lm4f_ep_stall_get(usbd_device *usbd_dev, uint8_t addr) +{ + (void)usbd_dev; + + const uint8_t ep = addr & 0x0f; + const bool dir_tx = addr & 0x80; + + if (ep == 0) { + return USB_CSRL0 & USB_CSRL0_STALLED; + } + + if (dir_tx) { + return USB_TXCSRL(ep) & USB_TXCSRL_STALLED; + } else { + return USB_RXCSRL(ep) & USB_RXCSRL_STALLED; + } +} + +static void lm4f_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak) +{ + (void)usbd_dev; + (void)addr; + (void)nak; + + /* NAK's are handled automatically by hardware. Move along. */ +} + +static uint16_t lm4f_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len) +{ + const uint8_t ep = addr & 0xf; + uint16_t i; + + (void)usbd_dev; + + /* Don't touch the FIFO if there is still a packet being transmitted */ + if (ep == 0 && (USB_CSRL0 & USB_CSRL0_TXRDY)) { + return 0; + } else if (USB_TXCSRL(ep) & USB_TXCSRL_TXRDY) { + return 0; + } + + /* + * We don't need to worry about buf not being aligned. If it's not, + * the reads are downgraded to 8-bit in hardware. We lose a bit of + * performance, but we don't crash. + */ + for (i = 0; i < (len & ~0x3); i += 4) { + USB_FIFO32(ep) = *((uint32_t *)(buf + i)); + } + if (len & 0x2) { + USB_FIFO16(ep) = *((uint16_t *)(buf + i)); + i += 2; + } + if (len & 0x1) { + USB_FIFO8(ep) = *((uint8_t *)(buf + i)); + i += 1; + } + + if (ep == 0) { + /* + * EP0 is very special. We should only set DATAEND when we + * transmit the last packet in the transaction. A transaction + * that is a multiple of 64 bytes will end with a zero-length + * packet, so our check is sane. + */ + if (len != 64) { + USB_CSRL0 |= USB_CSRL0_TXRDY | USB_CSRL0_DATAEND; + } else { + USB_CSRL0 |= USB_CSRL0_TXRDY; + } + } else { + USB_TXCSRL(ep) |= USB_TXCSRL_TXRDY; + } + + return i; +} + +static uint16_t lm4f_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len) +{ + (void)usbd_dev; + + uint16_t rlen; + uint8_t ep = addr & 0xf; + + uint16_t fifoin = USB_RXCOUNT(ep); + + rlen = (fifoin > len) ? len : fifoin; + + /* + * We don't need to worry about buf not being aligned. If it's not, + * the writes are downgraded to 8-bit in hardware. We lose a bit of + * performance, but we don't crash. + */ + for (len = 0; len < (rlen & ~0x3); len += 4) { + *((uint32_t *)(buf + len)) = USB_FIFO32(ep); + } + if (rlen & 0x2) { + *((uint16_t *)(buf + len)) = USB_FIFO16(ep); + len += 2; + } + if (rlen & 0x1) { + *((uint8_t *)(buf + len)) = USB_FIFO8(ep); + } + + if (ep == 0) { + /* + * Clear RXRDY + * Datasheet says that DATAEND must also be set when clearing + * RXRDY. We don't do that. If did this when transmitting a + * packet larger than 64 bytes, only the first 64 bytes would + * be transmitted, followed by a handshake. The host would only + * get 64 bytes, seeing it as a malformed packet. Usually, we + * would not get past enumeration. + */ + USB_CSRL0 |= USB_CSRL0_RXRDYC; + + } else { + USB_RXCSRL(ep) &= ~USB_RXCSRL_RXRDY; + } + + return rlen; +} + +static void lm4f_poll(usbd_device *usbd_dev) +{ + void (*tx_cb)(usbd_device *usbd_dev, uint8_t ea); + void (*rx_cb)(usbd_device *usbd_dev, uint8_t ea); + int i; + + /* + * The initial state of these registers might change, as we process the + * interrupt, but we need the initial state in order to decide how to + * handle events. + */ + const uint8_t usb_is = USB_IS; + const uint8_t usb_rxis = USB_RXIS; + const uint8_t usb_txis = USB_TXIS; + const uint8_t usb_csrl0 = USB_CSRL0; + + if ((usb_is & USB_IM_SUSPEND) && (usbd_dev->user_callback_suspend)) { + usbd_dev->user_callback_suspend(); + } + + if ((usb_is & USB_IM_RESUME) && (usbd_dev->user_callback_resume)) { + usbd_dev->user_callback_resume(); + } + + if (usb_is & USB_IM_RESET) { + _usbd_reset(usbd_dev); + } + + if ((usb_is & USB_IM_SOF) && (usbd_dev->user_callback_sof)) { + usbd_dev->user_callback_sof(); + } + + if (usb_txis & USB_EP0) { + /* + * The EP0 bit in USB_TXIS is special. It tells us that + * something happened on EP0, but does not tell us what. This + * bit does not necessarily tell us that a packet was + * transmitted, so we have to go through all the possibilities + * to figure out exactly what did. Only after we've exhausted + * all other possibilities, can we assume this is a EPO + * "transmit complete" interrupt. + */ + if (usb_csrl0 & USB_CSRL0_RXRDY) { + enum _usbd_transaction type; + type = (usbd_dev->control_state.state != DATA_OUT && + usbd_dev->control_state.state != LAST_DATA_OUT) + ? USB_TRANSACTION_SETUP : + USB_TRANSACTION_OUT; + + if (usbd_dev->user_callback_ctr[0][type]) { + usbd_dev-> + user_callback_ctr[0][type](usbd_dev, 0); + } + + + } else { + tx_cb = usbd_dev->user_callback_ctr[0] + [USB_TRANSACTION_IN]; + + /* + * EP0 bit in TXIS is set not only when a packet is + * finished transmitting, but also when RXRDY is set, or + * when we set TXRDY to transmit a packet. If any of + * those are the case, then we do not want to call our + * IN callback, since the state machine will be in the + * wrong state, and we'll just stall our control + * endpoint. + * In fact, the only way to know if it's time to call + * our TX callback is to know what to expect. The + * hardware does not tell us what sort of transaction + * this is. We need to work with the state machine to + * figure it all out. See [1] for details. + */ + if ((usbd_dev->control_state.state != DATA_IN) && + (usbd_dev->control_state.state != LAST_DATA_IN) && + (usbd_dev->control_state.state != STATUS_IN)) { + return; + } + + if (tx_cb) { + tx_cb(usbd_dev, 0); + } + } + } + + /* See which interrupt occurred */ + for (i = 1; i < 8; i++) { + tx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_IN]; + rx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_OUT]; + + if ((usb_txis & (1 << i)) && tx_cb) { + tx_cb(usbd_dev, i); + } + + if ((usb_rxis & (1 << i)) && rx_cb) { + rx_cb(usbd_dev, i); + } + } + + +} + +static void lm4f_disconnect(usbd_device *usbd_dev, bool disconnected) +{ + (void)usbd_dev; + + /* + * This is all it takes: + * usbd_disconnect(dev, 1) followed by usbd_disconnect(dev, 0) + * causes the device to re-enumerate and re-configure properly. + */ + if (disconnected) { + lm4f_usb_soft_disconnect(); + } else { + lm4f_usb_soft_connect(); + } +} + +/* + * A static struct works as long as we have only one USB peripheral. If we + * meet LM4Fs with more than one USB, then we need to rework this approach. + */ +static struct _usbd_device usbd_dev; + +/** Initialize the USB device controller hardware of the LM4F. */ +static usbd_device *lm4f_usbd_init(void) +{ + int i; + + /* Start the USB clock */ + periph_clock_enable(RCC_USB0); + /* Enable the USB PLL interrupts - used to assert PLL lock */ + SYSCTL_IMC |= (SYSCTL_IMC_USBPLLLIM | SYSCTL_IMC_PLLLIM); + rcc_usb_pll_on(); + + /* Make sure we're disconnected. We'll reconnect later */ + lm4f_usb_soft_disconnect(); + + /* Software reset USB */ + SYSCTL_SRUSB = 1; + for (i = 0; i < 1000; i++) { + __asm__("nop"); + } + SYSCTL_SRUSB = 0; + + /* + * Wait for the PLL to lock before soft connecting + * This will result in a deadlock if the system clock is not setup + * correctly (clock from main oscillator). + */ + /* Wait for it */ + i = 0; + while ((SYSCTL_RIS & SYSCTL_RIS_USBPLLLRIS) == 0) { + i++; + if (i > 0xffff) { + return 0; + } + } + + /* Now connect to USB */ + lm4f_usb_soft_connect(); + + /* No FIFO allocated yet, but the first 64 bytes are still reserved */ + usbd_dev.fifo_mem_top = 64; + + return &usbd_dev; +} + +/* What is this thing even good for */ +#define RX_FIFO_SIZE 512 + +const struct _usbd_driver lm4f_usb_driver = { + .init = lm4f_usbd_init, + .set_address = lm4f_set_address, + .ep_setup = lm4f_ep_setup, + .ep_reset = lm4f_endpoints_reset, + .ep_stall_set = lm4f_ep_stall_set, + .ep_stall_get = lm4f_ep_stall_get, + .ep_nak_set = lm4f_ep_nak_set, + .ep_write_packet = lm4f_ep_write_packet, + .ep_read_packet = lm4f_ep_read_packet, + .poll = lm4f_poll, + .disconnect = lm4f_disconnect, + .base_address = USB_BASE, + .set_address_before_status = false, + .rx_fifo_size = RX_FIFO_SIZE, +}; +/** + * @endcond + */ + +/** + * @} + */ diff --git a/libopencm3/lib/lpc13xx/Makefile b/libopencm3/lib/lpc13xx/Makefile new file mode 100644 index 0000000..f396d5b --- /dev/null +++ b/libopencm3/lib/lpc13xx/Makefile @@ -0,0 +1,40 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lpc13xx +SRCLIBDIR ?= .. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DLPC13XX +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o + +VPATH += ../cm3 + +include ../Makefile.include diff --git a/libopencm3/lib/lpc13xx/gpio.c b/libopencm3/lib/lpc13xx/gpio.c new file mode 100644 index 0000000..271572b --- /dev/null +++ b/libopencm3/lib/lpc13xx/gpio.c @@ -0,0 +1,42 @@ +/** @defgroup gpio_file GPIO + +@ingroup LPC13xx + +@brief libopencm3 LPC13xx General Purpose I/O + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +LGPL License Terms @ref lgpl_license +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +void gpio_set(uint32_t gpioport, uint16_t gpios) +{ + GPIO_DATA(gpioport) = gpios; +} + +/**@}*/ + diff --git a/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld b/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld new file mode 100644 index 0000000..bd0005c --- /dev/null +++ b/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC13XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/lpc17xx/Makefile b/libopencm3/lib/lpc17xx/Makefile new file mode 100644 index 0000000..4b49df4 --- /dev/null +++ b/libopencm3/lib/lpc17xx/Makefile @@ -0,0 +1,40 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lpc17xx +SRCLIBDIR ?= .. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -O0 -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DLPC17XX +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o + +VPATH += ../cm3 + +include ../Makefile.include diff --git a/libopencm3/lib/lpc17xx/gpio.c b/libopencm3/lib/lpc17xx/gpio.c new file mode 100644 index 0000000..4831af7 --- /dev/null +++ b/libopencm3/lib/lpc17xx/gpio.c @@ -0,0 +1,48 @@ +/** @defgroup gpio_file GPIO + +@ingroup LPC17xx + +@brief libopencm3 LPC17xx General Purpose I/O + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +void gpio_set(uint32_t gpioport, uint32_t gpios) +{ + GPIO_SET(gpioport) = gpios; +} + +void gpio_clear(uint32_t gpioport, uint32_t gpios) +{ + GPIO_CLR(gpioport) = gpios; +} + +/**@}*/ + diff --git a/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld b/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld new file mode 100644 index 0000000..bd0005c --- /dev/null +++ b/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC13XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/lpc43xx/gpio.c b/libopencm3/lib/lpc43xx/gpio.c new file mode 100644 index 0000000..935feb3 --- /dev/null +++ b/libopencm3/lib/lpc43xx/gpio.c @@ -0,0 +1,53 @@ +/** @defgroup gpio_file GPIO + +@ingroup LPC43xx + +@brief libopencm3 LPC43xx General Purpose I/O + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +void gpio_set(uint32_t gpioport, uint32_t gpios) +{ + GPIO_SET(gpioport) = gpios; +} + +void gpio_clear(uint32_t gpioport, uint32_t gpios) +{ + GPIO_CLR(gpioport) = gpios; +} + +void gpio_toggle(uint32_t gpioport, uint32_t gpios) +{ + GPIO_NOT(gpioport) = gpios; +} + +/**@}*/ + diff --git a/libopencm3/lib/lpc43xx/i2c.c b/libopencm3/lib/lpc43xx/i2c.c new file mode 100644 index 0000000..0d6c4c6 --- /dev/null +++ b/libopencm3/lib/lpc43xx/i2c.c @@ -0,0 +1,102 @@ +/** @defgroup i2c_file I2C + +@ingroup LPC43xx + +@brief libopencm3 LPC43xx I2C + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2012 Michael Ossmann + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Michael Ossmann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* + * This is a very minimal I2C driver just to make sure we can get the + * peripheral working. + */ + +/**@{*/ + +#include +#include +#include + +void i2c0_init(const uint16_t duty_cycle_count) +{ + /* enable input on SCL and SDA pins */ + SCU_SFSI2C0 = SCU_I2C0_NOMINAL; + + I2C0_SCLH = duty_cycle_count; + I2C0_SCLL = duty_cycle_count; + + /* clear the control bits */ + I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC + | I2C_CONCLR_STAC | I2C_CONCLR_I2ENC); + + /* enable I2C0 */ + I2C0_CONSET = I2C_CONSET_I2EN; +} + +/* transmit start bit */ +void i2c0_tx_start(void) +{ + I2C0_CONCLR = I2C_CONCLR_SIC; + I2C0_CONSET = I2C_CONSET_STA; + while (!(I2C0_CONSET & I2C_CONSET_SI)); + I2C0_CONCLR = I2C_CONCLR_STAC; +} + +/* transmit data byte */ +void i2c0_tx_byte(uint8_t byte) +{ + if (I2C0_CONSET & I2C_CONSET_STA) { + I2C0_CONCLR = I2C_CONCLR_STAC; + } + I2C0_DAT = byte; + I2C0_CONCLR = I2C_CONCLR_SIC; + while (!(I2C0_CONSET & I2C_CONSET_SI)); +} + +/* receive data byte */ +uint8_t i2c0_rx_byte(void) +{ + if (I2C0_CONSET & I2C_CONSET_STA) { + I2C0_CONCLR = I2C_CONCLR_STAC; + } + I2C0_CONCLR = I2C_CONCLR_SIC; + while (!(I2C0_CONSET & I2C_CONSET_SI)); + return I2C0_DAT; +} + +/* transmit stop bit */ +void i2c0_stop(void) +{ + if (I2C0_CONSET & I2C_CONSET_STA) { + I2C0_CONCLR = I2C_CONCLR_STAC; + } + I2C0_CONSET = I2C_CONSET_STO; + I2C0_CONCLR = I2C_CONCLR_SIC; +} + +/**@}*/ + diff --git a/libopencm3/lib/lpc43xx/ipc.c b/libopencm3/lib/lpc43xx/ipc.c new file mode 100644 index 0000000..c26931f --- /dev/null +++ b/libopencm3/lib/lpc43xx/ipc.c @@ -0,0 +1,58 @@ +/* +* This file is part of the libopencm3 project. +* +* Copyright (C) 2012 Benjamin Vernoux +* +* This library is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This library 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this library. If not, see . +*/ + +#include +#include +#include + +/* Set M0 in reset mode */ +void ipc_halt_m0(void) +{ + volatile uint32_t rst_active_status1; + + /* Check if M0 is reset by reading status */ + rst_active_status1 = RESET_ACTIVE_STATUS1; + + /* If the M0 has reset not asserted, halt it... */ + while (rst_active_status1 & RESET_CTRL1_M0APP_RST) { + RESET_CTRL1 = ((~rst_active_status1) | RESET_CTRL1_M0APP_RST); + rst_active_status1 = RESET_ACTIVE_STATUS1; + } +} + +void ipc_start_m0(uint32_t cm0_baseaddr) +{ + volatile uint32_t rst_active_status1; + + /* Set M0 memory mapping to point to start of M0 image */ + CREG_M0APPMEMMAP = cm0_baseaddr; + + /* Start/run M0 core */ + + /* Release Slave from reset, first read status */ + rst_active_status1 = RESET_ACTIVE_STATUS1; + + /* If the M0 is being held in reset, release it */ + /* 1 = no reset, 0 = reset */ + while (!(rst_active_status1 & RESET_CTRL1_M0APP_RST)) { + RESET_CTRL1 = ((~rst_active_status1) & ~RESET_CTRL1_M0APP_RST); + rst_active_status1 = RESET_ACTIVE_STATUS1; + } +} + diff --git a/libopencm3/lib/lpc43xx/m0/Makefile b/libopencm3/lib/lpc43xx/m0/Makefile new file mode 100644 index 0000000..65114c2 --- /dev/null +++ b/libopencm3/lib/lpc43xx/m0/Makefile @@ -0,0 +1,43 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 Michael Ossmann +## Copyright (C) 2012/2013 Benjamin Vernoux +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lpc43xx_m0 +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -O2 -g3 -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m0 -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DLPC43XX -DLPC43XX_M0 +# ARFLAGS = rcsv +ARFLAGS = rcs + +# LPC43xx common files for M4 / M0 +OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o + +#LPC43xx M0 specific file + Generic LPC43xx M4/M0 files +OBJS = $(OBJ_LPC43XX) + +VPATH += ../:../../cm3 + +include ../../Makefile.include diff --git a/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld new file mode 100644 index 0000000..e69de29 diff --git a/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld new file mode 100644 index 0000000..fedd3e1 --- /dev/null +++ b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld @@ -0,0 +1,96 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2012 Michael Ossmann + * Copyright (C) 2012 Benjamin Vernoux + * Copyright (C) 2012 Jared Boone + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC43XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + . = ORIGIN(ram_ahb2); + + .text : { + . = ALIGN(0x400); + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >ram_ahb2 + + /* exception index - required due to libgcc.a issuing /0 exceptions */ + __exidx_start = .; + .ARM.exidx : { + *(.ARM.exidx*) + } > ram_ahb2 + __exidx_end = .; + + _etext = .; + + . = ORIGIN(ram_ahb2); + + .data : { + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + } >ram_ahb2 + + _data = .; + _edata = .; + + .bss : { + _bss = .; + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram_ahb2 + + /* exception unwind data - required due to libgcc.a issuing /0 exceptions */ + .ARM.extab : { + *(.ARM.extab*) + } >ram_ahb2 + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support - discard it for now. + */ + /DISCARD/ : { *(.ARM.exidx) } + + end = .; + + /* Leave room above stack for IAP to run. */ + __StackTop = ORIGIN(ram_ahb2) + LENGTH(ram_ahb2) - 32; + PROVIDE(_stack = __StackTop); +} diff --git a/libopencm3/lib/lpc43xx/m4/Makefile b/libopencm3/lib/lpc43xx/m4/Makefile new file mode 100644 index 0000000..a3d3b03 --- /dev/null +++ b/libopencm3/lib/lpc43xx/m4/Makefile @@ -0,0 +1,50 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2012 Michael Ossmann +## Copyright (C) 2012 Benjamin Vernoux +## Copyright (C) 2013 Alexandru Gagniuc +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_lpc43xx +SRCLIBDIR ?= ../.. + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -O2 -g3 \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m4 -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD \ + $(FP_FLAGS) -DLPC43XX -DLPC43XX_M4 + +ARFLAGS = rcs + +# LPC43xx common files for M4 / M0 +OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o + +#LPC43xx M4 specific file + Generic LPC43xx M4/M0 files +OBJS = $(OBJ_LPC43XX) ipc.o + +VPATH += ../:../../cm3 + +include ../../Makefile.include diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld new file mode 100644 index 0000000..c289b35 --- /dev/null +++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld @@ -0,0 +1,127 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2012 Michael Ossmann + * Copyright (C) 2012 Benjamin Vernoux + * Copyright (C) 2012 Jared Boone + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC43XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + . = ALIGN(0x400); + _text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + + /* exception index - required due to libgcc.a issuing /0 exceptions */ + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + _etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + _etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + + . = ORIGIN(ram_local2); + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram_local2 AT >rom + _data_loadaddr = LOADADDR(.data); + + _data_rom = LOADADDR (.data) + ORIGIN(rom); + _edata_rom = _data_rom + SIZEOF (.data); + + .bss : { + _bss = .; + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram_local2 + + /* exception unwind data - required due to libgcc.a issuing /0 exceptions */ + .ARM.extab : { + *(.ARM.extab*) + } >ram_local2 + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; + + /* Leave room above stack for IAP to run. */ + __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32; + PROVIDE(_stack = __StackTop); +} diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld new file mode 100644 index 0000000..5bcdea6 --- /dev/null +++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld @@ -0,0 +1,139 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2012 Michael Ossmann + * Copyright (C) 2012 Benjamin Vernoux + * Copyright (C) 2012 Jared Boone + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC43XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + . = ORIGIN(ram_local1); + + .text : { + . = ALIGN(0x400); + _text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >ram_local1 + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >ram_local1 + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >ram_local1 + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >ram_local1 + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >ram_local1 + + /* exception index - required due to libgcc.a issuing /0 exceptions */ + __exidx_start = .; + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > ram_local1 + + . = ALIGN(4); + _etext = .; + _etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + _etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */ + + . = ORIGIN(ram_local2); + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram_local2 + _data_loadaddr = LOADADDR(.data); + + /* Running from RAM only, loading the .elf will initialize data for us. */ + _data_rom = .; + _edata_rom = .; + + _data = .; + _edata = .; + + .bss : { + _bss = .; + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram_local2 + + /* exception unwind data - required due to libgcc.a issuing /0 exceptions */ + .ARM.extab : { + *(.ARM.extab*) + } >ram_local2 + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support - discard it for now. + */ + /DISCARD/ : { *(.ARM.exidx) } + + end = .; + + /* Leave room above stack for IAP to run. */ + __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32; + PROVIDE(_stack = __StackTop); +} diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld new file mode 100644 index 0000000..e50040e --- /dev/null +++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld @@ -0,0 +1,128 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2012 Michael Ossmann + * Copyright (C) 2012 Benjamin Vernoux + * Copyright (C) 2012 Jared Boone + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for LPC43XX targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + . = ALIGN(0x400); + _text_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1); /* Start of Code in RAM */ + + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + + /* exception index - required due to libgcc.a issuing /0 exceptions */ + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + _etext_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1); + _etext_rom = (. - ORIGIN(rom)) + ORIGIN(rom_flash); + + . = ORIGIN(ram_local2); + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram_local2 AT >rom + _data_loadaddr = LOADADDR(.data); + + _data_rom = LOADADDR (.data) + ORIGIN(rom_flash); + _edata_rom = _data_rom + SIZEOF (.data); + + .bss : { + _bss = .; + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram_local2 + + /* exception unwind data - required due to libgcc.a issuing /0 exceptions */ + .ARM.extab : { + *(.ARM.extab*) + } >ram_local2 + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; + + /* Leave room above stack for IAP to run. */ + __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32; + PROVIDE(_stack = __StackTop); +} diff --git a/libopencm3/lib/lpc43xx/m4/vector_chipset.c b/libopencm3/lib/lpc43xx/m4/vector_chipset.c new file mode 100644 index 0000000..270e30e --- /dev/null +++ b/libopencm3/lib/lpc43xx/m4/vector_chipset.c @@ -0,0 +1,48 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * Copyright (C) 2012 Michael Ossmann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +extern unsigned _etext_ram, _text_ram, _etext_rom; + +#define CREG_M4MEMMAP MMIO32((0x40043000U + 0x100)) + +static void pre_main(void) +{ + volatile unsigned *src, *dest; + + /* Copy the code from ROM to Real RAM (if enabled) */ + if ((&_etext_ram-&_text_ram) > 0) { + src = &_etext_rom-(&_etext_ram-&_text_ram); + /* Change Shadow memory to ROM (for Debug Purpose in case Boot + * has not set correctly the M4MEMMAP because of debug) + */ + CREG_M4MEMMAP = (unsigned long)src; + + for (dest = &_text_ram; dest < &_etext_ram; ) { + *dest++ = *src++; + } + + /* Change Shadow memory to Real RAM */ + CREG_M4MEMMAP = (unsigned long)&_text_ram; + + /* Continue Execution in RAM */ + } +} diff --git a/libopencm3/lib/lpc43xx/scu.c b/libopencm3/lib/lpc43xx/scu.c new file mode 100644 index 0000000..c20cd84 --- /dev/null +++ b/libopencm3/lib/lpc43xx/scu.c @@ -0,0 +1,52 @@ +/** @defgroup scu_file System Control Unit + +@ingroup LPC43xx + +@brief libopencm3 LPC43xx System Control Unit + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2012 Benjamin Vernoux + +LGPL License Terms @ref lgpl_license +*/ + +/* +* This file is part of the libopencm3 project. +* +* Copyright (C) 2012 Benjamin Vernoux +* +* This library is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This library 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this library. If not, see . +*/ + +/**@{*/ + +#include + +/* For pin_conf_normal value see scu.h define SCU_CONF_XXX or Configuration for + * different I/O pins types + */ +void scu_pinmux(scu_grp_pin_t group_pin, uint32_t scu_conf) +{ + MMIO32(group_pin) = scu_conf; +} + +/* For other special SCU register USB1, I2C0, ADC0/1, DAC, EMC clock delay See + * scu.h + */ + +/* For Pin interrupt select register see scu.h SCU_PINTSEL0 & SCU_PINTSEL1 */ + +/**@}*/ + diff --git a/libopencm3/lib/lpc43xx/ssp.c b/libopencm3/lib/lpc43xx/ssp.c new file mode 100644 index 0000000..b63ec9b --- /dev/null +++ b/libopencm3/lib/lpc43xx/ssp.c @@ -0,0 +1,140 @@ +/** @defgroup ssp_file SSP + +@ingroup LPC43xx + +@brief libopencm3 LPC43xx SSP + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2012 Benjamin Vernoux + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Benjamin Vernoux + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include + +/* Disable SSP */ +void ssp_disable(ssp_num_t ssp_num) +{ + uint32_t ssp_port; + + if (ssp_num == SSP0_NUM) { + ssp_port = SSP0; + } else { + ssp_port = SSP1; + } + /* Disable SSP */ + SSP_CR1(ssp_port) = 0x0; +} + +/* +* SSP Init function +*/ +void ssp_init(ssp_num_t ssp_num, + ssp_datasize_t data_size, + ssp_frame_format_t frame_format, + ssp_cpol_cpha_t cpol_cpha_format, + uint8_t serial_clock_rate, + uint8_t clk_prescale, + ssp_mode_t mode, + ssp_master_slave_t master_slave, + ssp_slave_option_t slave_option) +{ + uint32_t ssp_port; + uint32_t clock; + + if (ssp_num == SSP0_NUM) { + ssp_port = SSP0; + } else { + ssp_port = SSP1; + } + + /* use PLL1 as clock source for SSP1 */ + CGU_BASE_SSP1_CLK = + CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1) + | CGU_BASE_SSP1_CLK_AUTOBLOCK; + + /* Disable SSP before to configure it */ + SSP_CR1(ssp_port) = 0x0; + + /* Configure SSP */ + clock = serial_clock_rate; + SSP_CPSR(ssp_port) = clk_prescale; + SSP_CR0(ssp_port) = + (data_size | frame_format | cpol_cpha_format | (clock<<8)); + + /* Enable SSP */ + SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option); +} + +static void ssp_wait_until_not_busy(ssp_num_t ssp_num) +{ + uint32_t ssp_port; + + if (ssp_num == SSP0_NUM) { + ssp_port = SSP0; + } else { + ssp_port = SSP1; + } + + while ((SSP_SR(ssp_port) & SSP_SR_BSY)); +} + +/* This Function Wait Data TX Ready, and Write Data to SSP */ +uint16_t ssp_transfer(ssp_num_t ssp_num, uint16_t data) +{ + uint32_t ssp_port; + + if (ssp_num == SSP0_NUM) { + ssp_port = SSP0; + } else { + ssp_port = SSP1; + } + + /* Wait Until FIFO not full */ + while ((SSP_SR(ssp_port) & SSP_SR_TNF) == 0); + + SSP_DR(ssp_port) = data; + + /* Wait for not busy, since we're controlling CS# of + * devices manually and need to wait for the data to + * be sent. It may also be important to wait here + * in case we're configuring devices via SPI and also + * with GPIO control -- we need to know when SPI + * commands are effective before altering a device's + * state with GPIO. I'm thinking the MAX2837, for + * example... + */ + ssp_wait_until_not_busy(ssp_num); + + /* Wait Until Data Received (Rx FIFO not Empty) */ + while ((SSP_SR(ssp_port) & SSP_SR_RNE) == 0); + + return SSP_DR(ssp_port); +} + + +/**@}*/ + diff --git a/libopencm3/lib/lpc43xx/timer.c b/libopencm3/lib/lpc43xx/timer.c new file mode 100644 index 0000000..f263c24 --- /dev/null +++ b/libopencm3/lib/lpc43xx/timer.c @@ -0,0 +1,72 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Ben Gamari + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + * This provides the code for the "next gen" EXTI block provided in F2/F4/L1 + * devices. (differences only in the source selection) + */ + +#include + +void timer_reset(uint32_t timer_peripheral) +{ + TIMER_TCR(timer_peripheral) |= TIMER_TCR_CRST; + TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CRST; +} + +void timer_enable_counter(uint32_t timer_peripheral) +{ + TIMER_TCR(timer_peripheral) |= TIMER_TCR_CEN; +} + +void timer_disable_counter(uint32_t timer_peripheral) +{ + TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CEN; +} + +void timer_set_counter(uint32_t timer_peripheral, uint32_t count) +{ + TIMER_TC(timer_peripheral) = count; +} + +uint32_t timer_get_counter(uint32_t timer_peripheral) +{ + return TIMER_TC(timer_peripheral); +} + +uint32_t timer_get_prescaler(uint32_t timer_peripheral) +{ + return TIMER_PR(timer_peripheral); +} + +void timer_set_prescaler(uint32_t timer_peripheral, uint32_t prescaler) +{ + TIMER_PR(timer_peripheral) = prescaler; +} + +void timer_set_mode(uint32_t timer_peripheral, uint32_t mode) +{ + TIMER_CTCR(timer_peripheral) = mode | + (TIMER_CTCR(timer_peripheral) & TIMER_CTCR_MODE_MASK); +} + +void timer_set_count_input(uint32_t timer_peripheral, uint32_t input) +{ + TIMER_CTCR(timer_peripheral) = input | + (TIMER_CTCR(timer_peripheral) & TIMER_CTCR_CINSEL_MASK); +} + diff --git a/libopencm3/lib/lpc43xx/uart.c b/libopencm3/lib/lpc43xx/uart.c new file mode 100644 index 0000000..3168ce2 --- /dev/null +++ b/libopencm3/lib/lpc43xx/uart.c @@ -0,0 +1,243 @@ +/* +* This file is part of the libopencm3 project. +* +* Copyright (C) 2012 Benjamin Vernoux +* +* This library is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This library 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this library. If not, see . +*/ + +#include +#include + +#define UART_SRC_32K 0x00 +#define UART_SRC_IRC 0x01 +#define UART_SRC_ENET_RX 0x02 +#define UART_SRC_ENET_TX 0x03 +#define UART_SRC_GP_CLKIN 0x04 +#define UART_SRC_XTAL 0x06 +#define UART_SRC_PLL0USB 0x07 +#define UART_SRC_PLL0AUDIO 0x08 +#define UART_SRC_PLL1 0x09 +#define UART_SRC_IDIVA 0x0C +#define UART_SRC_IDIVB 0x0D +#define UART_SRC_IDIVC 0x0E +#define UART_SRC_IDIVD 0x0F +#define UART_SRC_IDIVE 0x10 + +#define UART_CGU_AUTOBLOCK_CLOCK_BIT 11 +/* clock source selection (5 bits) */ +#define UART_CGU_BASE_CLK_SEL_SHIFT 24 + +uint32_t dummy_read; + +/* +* UART Init function +*/ +void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits, + uart_stopbit_t data_nb_stop, uart_parity_t data_parity, + uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval) +{ + uint32_t lcr_config; + uint32_t uart_port; + + uart_port = uart_num; + + switch (uart_num) { + case UART0_NUM: + /* use PLL1 as clock source for UART0 */ + CGU_BASE_UART0_CLK = (1< 0) { + counter++; + if (counter >= rx_timeout_nb_cycles) { + *error = UART_TIMEOUT_ERROR; + return 0; + } + } + } + + uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT); + + /* Clear error */ + *error = UART_NO_ERROR; + + return uart_val; +} + +/* This Function Wait Data TX Ready, and Write Data to UART + if rx_timeout_nb_cycles = 0 Infinite wait +*/ +void uart_write(uart_num_t uart_num, uint8_t data) +{ + uint32_t uart_port; + + uart_port = uart_num; + + /* Wait Until FIFO not full */ + while ((UART_LSR(uart_port) & UART_LSR_THRE) == 0); + + UART_THR(uart_port) = data; +} + diff --git a/libopencm3/lib/sam/3a/Makefile b/libopencm3/lib/sam/3a/Makefile new file mode 100644 index 0000000..d3e558c --- /dev/null +++ b/libopencm3/lib/sam/3a/Makefile @@ -0,0 +1,37 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_sam3a +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSAM3A +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o pmc.o usart.o + +VPATH += ../../usb:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/sam/3a/libopencm3_sam3a.ld b/libopencm3/lib/sam/3a/libopencm3_sam3a.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/sam/3a/libopencm3_sam3a.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/sam/3n/Makefile b/libopencm3/lib/sam/3n/Makefile new file mode 100644 index 0000000..e6d4ccf --- /dev/null +++ b/libopencm3/lib/sam/3n/Makefile @@ -0,0 +1,37 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_sam3n +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSAM3N +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o pmc.o usart.o + +VPATH += ../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/sam/3n/libopencm3_sam3n.ld b/libopencm3/lib/sam/3n/libopencm3_sam3n.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/sam/3n/libopencm3_sam3n.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/sam/3s/Makefile b/libopencm3/lib/sam/3s/Makefile new file mode 100644 index 0000000..45a8a7a --- /dev/null +++ b/libopencm3/lib/sam/3s/Makefile @@ -0,0 +1,38 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2014 Felix Held +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_sam3s +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSAM3S +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o pmc.o usart.o + +VPATH += ../../usb:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/sam/3s/libopencm3_sam3s.ld b/libopencm3/lib/sam/3s/libopencm3_sam3s.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/sam/3s/libopencm3_sam3s.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/sam/3u/Makefile b/libopencm3/lib/sam/3u/Makefile new file mode 100644 index 0000000..e0939f3 --- /dev/null +++ b/libopencm3/lib/sam/3u/Makefile @@ -0,0 +1,38 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2014 Felix Held +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_sam3u +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSAM3U +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o pmc.o usart.o + +VPATH += ../../usb:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/sam/3u/libopencm3_sam3u.ld b/libopencm3/lib/sam/3u/libopencm3_sam3u.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/sam/3u/libopencm3_sam3u.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/sam/3x/Makefile b/libopencm3/lib/sam/3x/Makefile new file mode 100644 index 0000000..de2fa28 --- /dev/null +++ b/libopencm3/lib/sam/3x/Makefile @@ -0,0 +1,37 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_sam3x +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSAM3X +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = gpio.o pmc.o usart.o + +VPATH += ../../usb:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/sam/3x/libopencm3_sam3x.ld b/libopencm3/lib/sam/3x/libopencm3_sam3x.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/sam/3x/libopencm3_sam3x.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/sam/common/gpio.c b/libopencm3/lib/sam/common/gpio.c new file mode 100644 index 0000000..75929f8 --- /dev/null +++ b/libopencm3/lib/sam/common/gpio.c @@ -0,0 +1,64 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +void gpio_init(uint32_t port, uint32_t pins, enum gpio_flags flags) +{ + switch (flags & 3) { + case GPIO_FLAG_GPINPUT: + /* input mode doesn't really exist, so we make a high + * output in open-drain mode + */ + PIO_SODR(port) = pins; + flags |= GPIO_FLAG_OPEN_DRAIN; + /* fall through */ + case GPIO_FLAG_GPOUTPUT: + PIO_OER(port) = pins; + PIO_PER(port) = pins; + break; + case GPIO_FLAG_PERIPHA: + PIO_ABSR(port) &= ~pins; + PIO_PDR(port) = pins; + break; + case GPIO_FLAG_PERIPHB: + PIO_ABSR(port) |= pins; + PIO_PDR(port) = pins; + } + + if (flags & GPIO_FLAG_OPEN_DRAIN) { + PIO_MDER(port) = pins; + } else { + PIO_MDDR(port) = pins; + } + + if (flags & GPIO_FLAG_PULL_UP) { + PIO_PUER(port) = pins; + } else { + PIO_PUDR(port) = pins; + } +} + +void gpio_toggle(uint32_t gpioport, uint32_t gpios) +{ + uint32_t odsr = PIO_ODSR(gpioport); + PIO_CODR(gpioport) = odsr & gpios; + PIO_SODR(gpioport) = ~odsr & gpios; +} + diff --git a/libopencm3/lib/sam/common/pmc.c b/libopencm3/lib/sam/common/pmc.c new file mode 100644 index 0000000..b4e0d7f --- /dev/null +++ b/libopencm3/lib/sam/common/pmc.c @@ -0,0 +1,97 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/** Default peripheral clock frequency after reset. */ +uint32_t pmc_mck_frequency = 4000000; + +void pmc_xtal_enable(bool en, uint8_t startup_time) +{ + if (en) { + CKGR_MOR = (CKGR_MOR & ~CKGR_MOR_MOSCXTST_MASK) | + CKGR_MOR_KEY | CKGR_MOR_MOSCXTEN | + (startup_time << 8); + while (!(PMC_SR & PMC_SR_MOSCXTS)); + } else { + CKGR_MOR = CKGR_MOR_KEY | (CKGR_MOR & ~CKGR_MOR_MOSCXTEN); + } +} + +void pmc_plla_config(uint8_t mul, uint8_t div) +{ + CKGR_PLLAR = CKGR_PLLAR_ONE | ((mul - 1) << 16) | + CKGR_PLLAR_PLLACOUNT_MASK | div; + while (!(PMC_SR & PMC_SR_LOCKA)); +} + +void pmc_peripheral_clock_enable(uint8_t pid) +{ + if (pid < 32) { + PMC_PCER0 = 1 << pid; + } else { + PMC_PCER1 = 1 << (pid & 31); + } +} + +void pmc_peripheral_clock_disable(uint8_t pid) +{ + if (pid < 32) { + PMC_PCDR0 = 1 << pid; + } else { + PMC_PCDR1 = 1 << (pid & 31); + } +} + +void pmc_mck_set_source(enum mck_src src) +{ + PMC_MCKR = (PMC_MCKR & ~PMC_MCKR_CSS_MASK) | src; + while (!(PMC_SR & PMC_SR_MCKRDY)); +} + +void pmc_clock_setup_in_xtal_12mhz_out_84mhz(void) +{ + eefc_set_latency(4); + + /* 12MHz external xtal, maximum possible startup time */ + pmc_xtal_enable(true, 0xff); + /* Select as main oscillator */ + CKGR_MOR |= CKGR_MOR_KEY | CKGR_MOR_MOSCSEL; + /* Multiply by 7 for 84MHz */ + pmc_plla_config(7, 1); + pmc_mck_set_source(MCK_SRC_PLLA); + + pmc_mck_frequency = 84000000; +} + +void pmc_clock_setup_in_rc_4mhz_out_84mhz(void) +{ + eefc_set_latency(4); + + /* Select as main oscillator */ + CKGR_MOR = CKGR_MOR_KEY | + (CKGR_MOR & ~(CKGR_MOR_MOSCSEL | CKGR_MOR_MOSCRCF_MASK)); + /* Multiply by 21 for 84MHz */ + pmc_plla_config(21, 1); + pmc_mck_set_source(MCK_SRC_PLLA); + + pmc_mck_frequency = 84000000; +} + diff --git a/libopencm3/lib/sam/common/usart.c b/libopencm3/lib/sam/common/usart.c new file mode 100644 index 0000000..36833f7 --- /dev/null +++ b/libopencm3/lib/sam/common/usart.c @@ -0,0 +1,110 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +void usart_set_baudrate(uint32_t usart, uint32_t baud) +{ + USART_BRGR(usart) = pmc_mck_frequency / (16 * baud); +} + +void usart_set_databits(uint32_t usart, int bits) +{ + USART_MR(usart) = (USART_MR(usart) & ~USART_MR_CHRL_MASK) | + ((bits - 5) << 6); +} + +void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb) +{ + USART_MR(usart) = (USART_MR(usart) & ~USART_MR_NBSTOP_MASK) | + (sb << 12); +} + +void usart_set_parity(uint32_t usart, enum usart_parity par) +{ + USART_MR(usart) = (USART_MR(usart) & ~USART_MR_PAR_MASK) | (par << 9); +} + +void usart_set_mode(uint32_t usart, enum usart_mode mode) +{ + USART_CR(usart) = + (mode & USART_MODE_RX) ? USART_CR_RXEN : USART_CR_RXDIS; + USART_CR(usart) = (mode & USART_MODE_TX) ? USART_CR_TXEN + : USART_CR_TXDIS; +} + +void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc) +{ + USART_MR(usart) = (USART_MR(usart) & ~USART_MR_MODE_MASK) | + (fc ? USART_MR_MODE_HW_HANDSHAKING : 0); +} + +void usart_enable(uint32_t usart) +{ + (void)usart; +} + +void usart_disable(uint32_t usart) +{ + (void)usart; +} + +void usart_send(uint32_t usart, uint16_t data) +{ + USART_THR(usart) = data; +} + +uint16_t usart_recv(uint32_t usart) +{ + return USART_RHR(usart) & 0x1f; +} + +void usart_wait_send_ready(uint32_t usart) +{ + while ((USART_CSR(usart) & USART_CSR_TXRDY) == 0); +} + +void usart_wait_recv_ready(uint32_t usart) +{ + while ((USART_CSR(usart) & USART_CSR_RXRDY) == 0); +} + +void usart_send_blocking(uint32_t usart, uint16_t data) +{ + usart_wait_send_ready(usart); + usart_send(usart, data); +} + +uint16_t usart_recv_blocking(uint32_t usart) +{ + usart_wait_recv_ready(usart); + + return usart_recv(usart); +} + +void usart_enable_rx_interrupt(uint32_t usart) +{ + USART_IER(usart) = USART_CSR_RXRDY; +} + +void usart_disable_rx_interrupt(uint32_t usart) +{ + USART_IDR(usart) = USART_CSR_RXRDY; +} diff --git a/libopencm3/lib/stm32/can.c b/libopencm3/lib/stm32/can.c new file mode 100644 index 0000000..d693a97 --- /dev/null +++ b/libopencm3/lib/stm32/can.c @@ -0,0 +1,557 @@ +/** @defgroup can_file CAN + +@ingroup STM32F_files + +@brief libopencm3 STM32Fxxx CAN + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 Piotr Esden-Tempski + +@date 12 November 2012 + +Devices can have up to two CAN peripherals. The peripherals support up to 1MBit +transmission rate. The peripheral has several filters for incoming messages that +can be distributed between two FIFOs and three transmit mailboxes. + +LGPL License Terms @ref lgpl_license +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#if defined(STM32F1) +# include +#elif defined(STM32F2) +# include +#elif defined(STM32F4) +# include +#else +# error "stm32 family not defined." +#endif + +/* Timeout for CAN INIT acknowledge + * this value is difficult to define. + * INIT is set latest after finishing the current transfer. + * Assuming the lowest CAN speed of 100kbps one CAN frame may take about 1.6ms + * WAIT loop timeout varies on compiler switches, optimization, CPU architecture + * and CPU speed + * + * The same timeout value is used for leaving INIT where the longest time is + * 11 bits(110 us on 100 kbps). + */ +#define CAN_MSR_INAK_TIMEOUT 0x0000FFFF + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Reset + +The CAN peripheral and all its associated configuration registers are placed in +the reset condition. The reset is effective via the RCC peripheral reset +system. + +@param[in] canport Unsigned int32. CAN block register address base @ref +can_reg_base. + */ +void can_reset(uint32_t canport) +{ + if (canport == CAN1) { + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST); + } else { + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Init + +Initialize the selected CAN peripheral block. + +@param[in] canport Unsigend int32. CAN register base address @ref can_reg_base. +@param[in] ttcm bool. Time triggered communication mode. +@param[in] abom bool. Automatic bus-off management. +@param[in] awum bool. Automatic wakeup mode. +@param[in] nart bool. No automatic retransmission. +@param[in] rflm bool. Receive FIFO locked mode. +@param[in] txfp bool. Transmit FIFO priority. +@param[in] sjw Unsigned int32. Resynchronization time quanta jump width. +@param[in] ts1 Unsigned int32. Time segment 1 time quanta width. +@param[in] ts2 Unsigned int32. Time segment 2 time quanta width. +@param[in] brp Unsigned int32. Baud rate prescaler. +@returns int 0 on success, 1 on initialization failure. +*/ +int can_init(uint32_t canport, bool ttcm, bool abom, bool awum, bool nart, + bool rflm, bool txfp, uint32_t sjw, uint32_t ts1, uint32_t ts2, + uint32_t brp, bool loopback, bool silent) +{ + volatile uint32_t wait_ack; + int ret = 0; + + /* Exit from sleep mode. */ + CAN_MCR(canport) &= ~CAN_MCR_SLEEP; + + /* Request initialization "enter". */ + CAN_MCR(canport) |= CAN_MCR_INRQ; + + /* Wait for acknowledge. */ + wait_ack = CAN_MSR_INAK_TIMEOUT; + while ((--wait_ack) && + ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK)); + + /* Check the acknowledge. */ + if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK) { + return 1; + } + + /* clear can timing bits */ + CAN_BTR(canport) = 0; + + /* Set the automatic bus-off management. */ + if (ttcm) { + CAN_MCR(canport) |= CAN_MCR_TTCM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_TTCM; + } + + if (abom) { + CAN_MCR(canport) |= CAN_MCR_ABOM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_ABOM; + } + + if (awum) { + CAN_MCR(canport) |= CAN_MCR_AWUM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_AWUM; + } + + if (nart) { + CAN_MCR(canport) |= CAN_MCR_NART; + } else { + CAN_MCR(canport) &= ~CAN_MCR_NART; + } + + if (rflm) { + CAN_MCR(canport) |= CAN_MCR_RFLM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_RFLM; + } + + if (txfp) { + CAN_MCR(canport) |= CAN_MCR_TXFP; + } else { + CAN_MCR(canport) &= ~CAN_MCR_TXFP; + } + + if (silent) { + CAN_BTR(canport) |= CAN_BTR_SILM; + } else { + CAN_BTR(canport) &= ~CAN_BTR_SILM; + } + + if (loopback) { + CAN_BTR(canport) |= CAN_BTR_LBKM; + } else { + CAN_BTR(canport) &= ~CAN_BTR_LBKM; + } + + /* Set bit timings. */ + CAN_BTR(canport) |= sjw | ts2 | ts1 | + ((brp - 1ul) & CAN_BTR_BRP_MASK); + + /* Request initialization "leave". */ + CAN_MCR(canport) &= ~CAN_MCR_INRQ; + + /* Wait for acknowledge. */ + wait_ack = CAN_MSR_INAK_TIMEOUT; + while ((--wait_ack) && + ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK)); + + if ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK) { + ret = 1; + } + + return ret; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Filter Init + +Initialize incoming message filter and assign to FIFO. + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] nr Unsigned int32. ID number of the filter. +@param[in] scale_32bit bool. 32-bit scale for the filter? +@param[in] id_list_mode bool. ID list filter mode? +@param[in] fr1 Unsigned int32. First filter register content. +@param[in] fr2 Unsigned int32. Second filter register content. +@param[in] fifo Unsigned int32. FIFO id. +@param[in] enable bool. Enable filter? + */ +void can_filter_init(uint32_t canport, uint32_t nr, bool scale_32bit, + bool id_list_mode, uint32_t fr1, uint32_t fr2, + uint32_t fifo, bool enable) +{ + uint32_t filter_select_bit = 0x00000001 << nr; + + /* Request initialization "enter". */ + CAN_FMR(canport) |= CAN_FMR_FINIT; + + /* Deactivate the filter. */ + CAN_FA1R(canport) &= ~filter_select_bit; + + if (scale_32bit) { + /* Set 32-bit scale for the filter. */ + CAN_FS1R(canport) |= filter_select_bit; + } else { + /* Set 16-bit scale for the filter. */ + CAN_FS1R(canport) &= ~filter_select_bit; + } + + if (id_list_mode) { + /* Set filter mode to ID list mode. */ + CAN_FM1R(canport) |= filter_select_bit; + } else { + /* Set filter mode to id/mask mode. */ + CAN_FM1R(canport) &= ~filter_select_bit; + } + + /* Set the first filter register. */ + CAN_FiR1(canport, nr) = fr1; + + /* Set the second filter register. */ + CAN_FiR2(canport, nr) = fr2; + + /* Select FIFO0 or FIFO1 as filter assignement. */ + if (fifo) { + CAN_FFA1R(canport) |= filter_select_bit; /* FIFO1 */ + } else { + CAN_FFA1R(canport) &= ~filter_select_bit; /* FIFO0 */ + } + + if (enable) { + CAN_FA1R(canport) |= filter_select_bit; /* Activate filter. */ + } + + /* Request initialization "leave". */ + CAN_FMR(canport) &= ~CAN_FMR_FINIT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Initialize a 16bit Message ID Mask Filter + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] nr Unsigned int32. ID number of the filter. +@param[in] id1 Unsigned int16. First message ID to filter. +@param[in] mask1 Unsigned int16. First message ID bit mask. +@param[in] id2 Unsigned int16. Second message ID to filter. +@param[in] mask2 Unsigned int16. Second message ID bit mask. +@param[in] fifo Unsigned int32. FIFO id. +@param[in] enable bool. Enable filter? + */ +void can_filter_id_mask_16bit_init(uint32_t canport, uint32_t nr, uint16_t id1, + uint16_t mask1, uint16_t id2, + uint16_t mask2, uint32_t fifo, bool enable) +{ + can_filter_init(canport, nr, false, false, + ((uint32_t)id1 << 16) | (uint32_t)mask1, + ((uint32_t)id2 << 16) | (uint32_t)mask2, fifo, enable); +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Initialize a 32bit Message ID Mask Filter + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] nr Unsigned int32. ID number of the filter. +@param[in] id Unsigned int32. Message ID to filter. +@param[in] mask Unsigned int32. Message ID bit mask. +@param[in] fifo Unsigned int32. FIFO id. +@param[in] enable bool. Enable filter? + */ +void can_filter_id_mask_32bit_init(uint32_t canport, uint32_t nr, uint32_t id, + uint32_t mask, uint32_t fifo, bool enable) +{ + can_filter_init(canport, nr, true, false, id, mask, fifo, enable); +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Initialize a 16bit Message ID List Filter + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] nr Unsigned int32. ID number of the filter. +@param[in] id1 Unsigned int16. First message ID to match. +@param[in] id2 Unsigned int16. Second message ID to match. +@param[in] id3 Unsigned int16. Third message ID to match. +@param[in] id4 Unsigned int16. Fourth message ID to match. +@param[in] fifo Unsigned int32. FIFO id. +@param[in] enable bool. Enable filter? + */ +void can_filter_id_list_16bit_init(uint32_t canport, uint32_t nr, + uint16_t id1, uint16_t id2, + uint16_t id3, uint16_t id4, + uint32_t fifo, bool enable) +{ + can_filter_init(canport, nr, false, true, + ((uint32_t)id1 << 16) | (uint32_t)id2, + ((uint32_t)id3 << 16) | (uint32_t)id4, fifo, enable); +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Initialize a 32bit Message ID List Filter + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] nr Unsigned int32. ID number of the filter. +@param[in] id1 Unsigned int32. First message ID to match. +@param[in] id2 Unsigned int32. Second message ID to match. +@param[in] fifo Unsigned int32. FIFO id. +@param[in] enable bool. Enable filter? + */ +void can_filter_id_list_32bit_init(uint32_t canport, uint32_t nr, + uint32_t id1, uint32_t id2, + uint32_t fifo, bool enable) +{ + can_filter_init(canport, nr, true, true, id1, id2, fifo, enable); +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Enable IRQ + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] irq Unsigned int32. IRQ bit(s). + */ +void can_enable_irq(uint32_t canport, uint32_t irq) +{ + CAN_IER(canport) |= irq; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Disable IRQ + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] irq Unsigned int32. IRQ bit(s). + */ +void can_disable_irq(uint32_t canport, uint32_t irq) +{ + CAN_IER(canport) &= ~irq; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Transmit Message + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] id Unsigned int32. Message ID. +@param[in] ext bool. Extended message ID? +@param[in] rtr bool. Request transmit? +@param[in] length Unsigned int8. Message payload length. +@param[in] data Unsigned int8[]. Message payload data. +@returns int 0, 1 or 2 on success and depending on which outgoing mailbox got +selected. -1 if no mailbox was available and no transmission got queued. + */ +int can_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr, + uint8_t length, uint8_t *data) +{ + int ret = 0; + uint32_t mailbox = 0; + union { + uint8_t data8[4]; + uint32_t data32; + } tdlxr, tdhxr; + + /* Check which transmit mailbox is empty if any. */ + if ((CAN_TSR(canport) & CAN_TSR_TME0) == CAN_TSR_TME0) { + ret = 0; + mailbox = CAN_MBOX0; + } else if ((CAN_TSR(canport) & CAN_TSR_TME1) == CAN_TSR_TME1) { + ret = 1; + mailbox = CAN_MBOX1; + } else if ((CAN_TSR(canport) & CAN_TSR_TME2) == CAN_TSR_TME2) { + ret = 2; + mailbox = CAN_MBOX2; + } else { + ret = -1; + } + + /* If we have no empty mailbox return with an error. */ + if (ret == -1) { + return ret; + } + + if (ext) { + /* Set extended ID. */ + CAN_TIxR(canport, mailbox) = (id << CAN_TIxR_EXID_SHIFT) | + CAN_TIxR_IDE; + } else { + /* Set standard ID. */ + CAN_TIxR(canport, mailbox) = id << CAN_TIxR_STID_SHIFT; + } + + /* Set/clear remote transmission request bit. */ + if (rtr) { + CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; /* Set */ + } + + /* Set the DLC. */ + CAN_TDTxR(canport, mailbox) &= ~CAN_TDTxR_DLC_MASK; + CAN_TDTxR(canport, mailbox) |= (length & CAN_TDTxR_DLC_MASK); + + switch (length) { + case 8: + tdhxr.data8[3] = data[7]; + /* no break */ + case 7: + tdhxr.data8[2] = data[6]; + /* no break */ + case 6: + tdhxr.data8[1] = data[5]; + /* no break */ + case 5: + tdhxr.data8[0] = data[4]; + /* no break */ + case 4: + tdlxr.data8[3] = data[3]; + /* no break */ + case 3: + tdlxr.data8[2] = data[2]; + /* no break */ + case 2: + tdlxr.data8[1] = data[1]; + /* no break */ + case 1: + tdlxr.data8[0] = data[0]; + /* no break */ + default: + break; + } + /* Set the data. */ + + CAN_TDLxR(canport, mailbox) = tdlxr.data32; + CAN_TDHxR(canport, mailbox) = tdhxr.data32; + + /* Request transmission. */ + CAN_TIxR(canport, mailbox) |= CAN_TIxR_TXRQ; + + return ret; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Release FIFO + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] fifo Unsigned int8. FIFO id. + */ +void can_fifo_release(uint32_t canport, uint8_t fifo) +{ + if (fifo == 0) { + CAN_RF0R(canport) |= CAN_RF1R_RFOM1; + } else { + CAN_RF1R(canport) |= CAN_RF1R_RFOM1; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief CAN Receive Message + +@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base. +@param[in] fifo Unsigned int8. FIFO id. +@param[in] release bool. Release the FIFO automatically after coping data out. +@param[out] id Unsigned int32 pointer. Message ID. +@param[out] ext bool pointer. The message ID is extended? +@param[out] rtr bool pointer. Request of transmission? +@param[out] fmi Unsigned int32 pointer. ID of the matched filter. +@param[out] length Unsigned int8 pointer. Length of message payload. +@param[out] data Unsigned int8[]. Message payload data. + */ +void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id, + bool *ext, bool *rtr, uint32_t *fmi, uint8_t *length, + uint8_t *data) +{ + uint32_t fifo_id = 0; + union { + uint8_t data8[4]; + uint32_t data32; + } rdlxr, rdhxr; + const uint32_t fifoid_array[2] = {CAN_FIFO0, CAN_FIFO1}; + + fifo_id = fifoid_array[fifo]; + + /* Get type of CAN ID and CAN ID. */ + if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_IDE) { + *ext = true; + /* Get extended CAN ID. */ + *id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_EXID_SHIFT) & + CAN_RIxR_EXID_MASK; + } else { + *ext = false; + /* Get standard CAN ID. */ + *id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_STID_SHIFT) & + CAN_RIxR_STID_MASK; + } + + /* Get remote transmit flag. */ + if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_RTR) { + *rtr = true; + } else { + *rtr = false; + } + + /* Get filter match ID. */ + *fmi = ((CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_FMI_MASK) >> + CAN_RDTxR_FMI_SHIFT); + + /* Get data length. */ + *length = CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_DLC_MASK; + /* accelerate reception by copying the CAN data from the controller + * memory to the fast internal RAM + */ + + rdlxr.data32 = CAN_RDLxR(canport, fifo_id); + rdhxr.data32 = CAN_RDHxR(canport, fifo_id); + /* */ + /* Get data. + * Byte wise copy is needed because we do not know the alignment + * of the input buffer. + * Here copying 8 bytes unconditionally is faster than using loop + * + * It is OK to copy all 8 bytes because the upper layer must be + * prepared for data length bigger expected. + * In contrary the driver has no information about the intended size. + * This could be different if the max length would be handed over + * to the function, but it is not the case + */ + data[0] = rdlxr.data8[0]; + data[1] = rdlxr.data8[1]; + data[2] = rdlxr.data8[2]; + data[3] = rdlxr.data8[3]; + data[4] = rdhxr.data8[0]; + data[5] = rdhxr.data8[1]; + data[6] = rdhxr.data8[2]; + data[7] = rdhxr.data8[3]; + + /* Release the FIFO. */ + if (release) { + can_fifo_release(canport, fifo); + } +} + +bool can_available_mailbox(uint32_t canport) +{ + return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2); +} diff --git a/libopencm3/lib/stm32/common/adc_common_v1.c b/libopencm3/lib/stm32/common/adc_common_v1.c new file mode 100644 index 0000000..a4b9257 --- /dev/null +++ b/libopencm3/lib/stm32/common/adc_common_v1.c @@ -0,0 +1,755 @@ +/** @addtogroup adc_file + +@author @htmlonly © @endhtmlonly +2009 Edward Cheeseman +@author @htmlonly © @endhtmlonly +2012 Ken Sarkies +@author @htmlonly © @endhtmlonly +2014 Karl Palsson + +This library supports one style of the Analog to Digital Conversion System in +the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics. + +The style of ADC Peripheral supported by this code is found in the F1, F2, +F37x, F38x, F4, and L1 series devices (at the time of writing) but is quite +different to the style found on the F0 and F30x and F31x. +Devices can have up to three A/D converters each with their own set of +registers. +However all the A/D converters share a common clock. On most devices, this is +prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum +of 8, though on the L1 this is always a divider from the HSI. (And therefore HSI +_must_ be enabled before attempting to enable the ADC) + +Each A/D converter has up to ADC_MAX_CHANNELS channels: +@li On ADC1 the analog channels 16 and 17 are internally connected to the +temperature sensor and VREFINT, respectively. +@li On ADC2 (if available) the analog channels 16 and 17 are internally +connected to VSS. +@li On ADC3 (if available) the analog channels 9, 14, 15, 16 and 17 are +internally connected to VSS. + +The conversions can occur as a one-off conversion whereby the process stops once +conversion is complete. The conversions can also be continuous wherein a new +conversion starts immediately the previous conversion has ended. + +Conversion can occur as a single channel conversion or a scan of a group of +channels in either continuous or one-off mode. If more than one channel is +converted in a scan group, DMA must be used to transfer the data as there is +only one result register available. An interrupt can be set to occur at the end +of conversion, which occurs after all channels have been scanned. + +A discontinuous mode allows a subgroup of group of a channels to be converted in +bursts of a given length. + +Injected conversions allow a second group of channels to be converted separately +from the regular group. An interrupt can be set to occur at the end of +conversion, which occurs after all channels have been scanned. + +@section adc_api_ex Basic ADC Handling API. + +Example 1: Simple single channel conversion polled. Enable the peripheral clock +and ADC, reset ADC and set the prescaler divider. Set dual mode to independent +(default). Enable triggering for a software trigger. + +@code + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); + adc_off(ADC1); + rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); + rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); + adc_set_dual_mode(ADC_CR1_DUALMOD_IND); + adc_disable_scan_mode(ADC1); + adc_set_single_conversion_mode(ADC1); + adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC); + adc_set_single_channel(ADC1, ADC_CHANNEL0); + adc_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART); + adc_power_on(ADC1); + adc_reset_calibration(ADC1); + adc_calibration(ADC1); + adc_start_conversion_regular(ADC1); + while (! adc_eoc(ADC1)); + reg16 = adc_read_regular(ADC1); +@endcode + +LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Off + +Turn off the ADC to reduce power consumption to a few microamps. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_off(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_ADON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for Regular Conversions + +The analog watchdog allows the monitoring of an analog signal between two +threshold levels. The thresholds must be preset. Comparison is done before data +alignment takes place, so the thresholds are left-aligned. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_enable_analog_watchdog_regular(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_AWDEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog for Regular Conversions + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_disable_analog_watchdog_regular(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_AWDEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for Injected Conversions + +The analog watchdog allows the monitoring of an analog signal between two +threshold levels. The thresholds must be preset. Comparison is done before data +alignment takes place, so the thresholds are left-aligned. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_analog_watchdog_injected(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_JAWDEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog for Injected Conversions + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_analog_watchdog_injected(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_JAWDEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Discontinuous Mode for Regular Conversions + +In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the +defined regular channel group. The subgroup is defined by the number of +consecutive channels to be converted. After a subgroup has been converted +the next trigger will start conversion of the immediately following subgroup +of the same length or until the whole group has all been converted. When the +the whole group has been converted, the next trigger will restart conversion +of the subgroup at the beginning of the whole group. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] length Unsigned int8. Number of channels in the group @ref +adc_cr1_discnum +*/ + +void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length) +{ + if ((length-1) > 7) { + return; + } + ADC_CR1(adc) |= ADC_CR1_DISCEN; + ADC_CR1(adc) |= ((length-1) << ADC_CR1_DISCNUM_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Discontinuous Mode for Regular Conversions + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_discontinuous_mode_regular(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_DISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Discontinuous Mode for Injected Conversions + +In this mode the ADC converts sequentially one channel of the defined group of +injected channels, cycling back to the first channel in the group once the +entire group has been converted. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_discontinuous_mode_injected(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_JDISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Discontinuous Mode for Injected Conversions + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_discontinuous_mode_injected(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_JDISCEN; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Automatic Injected Conversions + +The ADC converts a defined injected group of channels immediately after the +regular channels have been converted. The external trigger on the injected +channels is disabled as required. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_automatic_injected_group_conversion(uint32_t adc) +{ + adc_disable_external_trigger_injected(adc); + ADC_CR1(adc) |= ADC_CR1_JAUTO; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Automatic Injected Conversions + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_automatic_injected_group_conversion(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_JAUTO; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels + +The analog watchdog allows the monitoring of an analog signal between two +threshold levels. The thresholds must be preset. Comparison is done before data +alignment takes place, so the thresholds are left-aligned. + +@note The analog watchdog must be enabled for either or both of the regular or +injected channels. If neither are enabled, the analog watchdog feature will be +disabled. +@ref adc_enable_analog_watchdog_injected, @ref +adc_enable_analog_watchdog_regular. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_analog_watchdog_on_all_channels(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_AWDSGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for a Selected Channel + +The analog watchdog allows the monitoring of an analog signal between two +threshold levels. The thresholds must be preset. Comparison is done before data +alignment takes place, so the thresholds are left-aligned. + +@note The analog watchdog must be enabled for either or both of the regular or +injected channels. If neither are enabled, the analog watchdog feature will be +disabled. If both are enabled, the same channel number is monitored. +@ref adc_enable_analog_watchdog_injected, @ref +adc_enable_analog_watchdog_regular. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] channel Unsigned int8. ADC channel number @ref adc_watchdog_channel +*/ + +void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, + uint8_t channel) +{ + uint32_t reg32; + + reg32 = (ADC_CR1(adc) & ~ADC_CR1_AWDCH_MASK); /* Clear bits [4:0]. */ + if (channel <= ADC_CR1_AWDCH_MAX) { + reg32 |= channel; + } + ADC_CR1(adc) = reg32; + ADC_CR1(adc) |= ADC_CR1_AWDSGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Scan Mode + +In this mode a conversion consists of a scan of the predefined set of channels, +regular and injected, each channel conversion immediately following the +previous one. It can use single, continuous or discontinuous mode. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_scan_mode(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_SCAN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Scan Mode + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_scan_mode(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_SCAN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Injected End-Of-Conversion Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_eoc_interrupt_injected(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_JEOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Injected End-Of-Conversion Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_eoc_interrupt_injected(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_JEOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_awd_interrupt(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_AWDIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_awd_interrupt(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_AWDIE; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Regular End-Of-Conversion Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_eoc_interrupt(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_EOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Regular End-Of-Conversion Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_eoc_interrupt(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_EOCIE; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Left Aligned + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_set_left_aligned(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Right Aligned + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_set_right_aligned(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the End-of-Conversion Flag + +This flag is set after all channels of a regular or injected group have been +converted. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns bool. End of conversion flag. +*/ + +bool adc_eoc(uint32_t adc) +{ + return (ADC_SR(adc) & ADC_SR_EOC) != 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion + +This flag is set after all channels of an injected group have been converted. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns bool. End of conversion flag. +*/ + +bool adc_eoc_injected(uint32_t adc) +{ + return (ADC_SR(adc) & ADC_SR_JEOC) != 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read from the Regular Conversion Result Register + +The result read back is 12 bits, right or left aligned within the first 16 bits. +For ADC1 only, the higher 16 bits will hold the result from ADC2 if +an appropriate dual mode has been set @see adc_set_dual_mode. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns Unsigned int32 conversion result. +*/ + +uint32_t adc_read_regular(uint32_t adc) +{ + return ADC_DR(adc); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read from an Injected Conversion Result Register + +The result read back from the selected injected result register (one of four) +is 12 bits, right or left aligned within the first 16 bits. The result can have +a negative value if the injected channel offset has been set @see +adc_set_injected_offset. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] reg Unsigned int8. Register number (1 ... 4). +@returns Unsigned int32 conversion result. +*/ + +uint32_t adc_read_injected(uint32_t adc, uint8_t reg) +{ + switch (reg) { + case 1: + return ADC_JDR1(adc); + case 2: + return ADC_JDR2(adc); + case 3: + return ADC_JDR3(adc); + case 4: + return ADC_JDR4(adc); + } + return 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Continuous Conversion Mode + +In this mode the ADC starts a new conversion of a single channel or a channel +group immediately following completion of the previous channel group conversion. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_set_continuous_conversion_mode(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_CONT; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Single Conversion Mode + +In this mode the ADC performs a conversion of one channel or a channel group +and stops. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_set_single_conversion_mode(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_CONT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Upper Threshold + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] threshold Unsigned int8. Upper threshold value +*/ + +void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold) +{ + uint32_t reg32 = 0; + + reg32 = (uint32_t)threshold; + reg32 &= ADC_HT_MSK; + ADC_HTR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Lower Threshold + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] threshold Unsigned int8. Lower threshold value +*/ + +void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold) +{ + uint32_t reg32 = 0; + + reg32 = (uint32_t)threshold; + reg32 &= ADC_LT_MSK; + ADC_LTR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ + +/** @brief ADC Set a Regular Channel Conversion Sequence + +Define a sequence of channels to be converted as a regular group with a length +from 1 to ADC_REGULAR_SEQUENCE_MAX channels. If this is called during +conversion, the current conversion is reset and conversion begins again with +the newly defined group. + +@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base. +@param[in] length Unsigned int8. Number of channels in the group. +@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..31. + */ + +void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[]) +{ + uint32_t fifth6 = 0; + uint32_t fourth6 = 0; + uint32_t third6 = 0; + uint32_t second6 = 0; + uint32_t first6 = 0; + uint8_t i = 0; + + if (length > ADC_SQR_MAX_CHANNELS_REGULAR) { + return; + } + + for (i = 1; i <= length; i++) { + if (i <= 6) { + first6 |= (channel[i - 1] << ((i - 1) * 5)); + } + if ((i > 6) & (i <= 12)) { + second6 |= (channel[i - 1] << ((i - 6 - 1) * 5)); + } + if ((i > 12) & (i <= 18)) { + third6 |= (channel[i - 1] << ((i - 12 - 1) * 5)); + } + if ((i > 18) & (i <= 24)) { + fourth6 |= (channel[i - 1] << ((i - 18 - 1) * 5)); + } + if ((i > 24) & (i <= 28)) { + fifth6 |= (channel[i - 1] << ((i - 24 - 1) * 5)); + } + } +#if defined(ADC_SQR5) + ADC_SQR1(adc) = fifth6 | ((length - 1) << ADC_SQR1_L_LSB); + ADC_SQR2(adc) = fourth6; + ADC_SQR3(adc) = third6; + ADC_SQR4(adc) = second6; + ADC_SQR5(adc) = first6; +#else + ADC_SQR1(adc) = third6 | ((length - 1) << ADC_SQR1_L_LSB); + ADC_SQR2(adc) = second6; + ADC_SQR3(adc) = first6; +#endif +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set an Injected Channel Conversion Sequence + +Defines a sequence of channels to be converted as an injected group with a +length from 1 to 4 channels. If this is called during conversion, the current +conversion is reset and conversion begins again with the newly defined group. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] length Unsigned int8. Number of channels in the group. +@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18 +*/ + +void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[]) +{ + uint32_t reg32 = 0; + uint8_t i = 0; + + /* Maximum sequence length is 4 channels. Minimum sequence is 1.*/ + if ((length - 1) > 3) { + return; + } + + for (i = 0; i < length; i++) { + reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]); + } + + reg32 |= ADC_JSQR_JL_VAL(length); + + ADC_JSQR(adc) = reg32; +} + + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Set the Injected Channel Data Offset + +This value is subtracted from the injected channel results after conversion is +complete, and can result in negative results. A separate value can be specified +for each injected data register. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] reg Unsigned int8. Register number (1 ... 4). +@param[in] offset Unsigned int32. +*/ + +void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset) +{ + switch (reg) { + case 1: + ADC_JOFR1(adc) = offset; + break; + case 2: + ADC_JOFR2(adc) = offset; + break; + case 3: + ADC_JOFR3(adc) = offset; + break; + case 4: + ADC_JOFR4(adc) = offset; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Software Triggered Conversion on Regular Channels + +This starts conversion on a set of defined regular channels if the ADC trigger +is set to be a software trigger. It is cleared by hardware once conversion +starts. + +Special F1 Note this is a software trigger and requires triggering to be +enabled and the trigger source to be set appropriately otherwise conversion +will not start. This is not the same as the ADC start conversion operation. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_start_conversion_regular(uint32_t adc) +{ + /* Start conversion on regular channels. */ + ADC_CR2(adc) |= ADC_CR2_SWSTART; + + /* Wait until the ADC starts the conversion. */ + while (ADC_CR2(adc) & ADC_CR2_SWSTART); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Software Triggered Conversion on Injected Channels + +This starts conversion on a set of defined injected channels if the ADC trigger +is set to be a software trigger. It is cleared by hardware once conversion +starts. + +Special F1 Note this is a software trigger and requires triggering to be +enabled and the trigger source to be set appropriately otherwise conversion +will not start. This is not the same as the ADC start conversion operation. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_start_conversion_injected(uint32_t adc) +{ + /* Start conversion on injected channels. */ + ADC_CR2(adc) |= ADC_CR2_JSWSTART; + + /* Wait until the ADC starts the conversion. */ + while (ADC_CR2(adc) & ADC_CR2_JSWSTART); +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable DMA Transfers + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_dma(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_DMA; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable DMA Transfers + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_dma(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_DMA; +} + + + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/crc_common_all.c b/libopencm3/lib/stm32/common/crc_common_all.c new file mode 100644 index 0000000..5794c8f --- /dev/null +++ b/libopencm3/lib/stm32/common/crc_common_all.c @@ -0,0 +1,81 @@ +/** @addtogroup crc_file + +@author @htmlonly © @endhtmlonly 2012 Karl Palsson + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief CRC Reset. + +Reset the CRC unit and forces the data register to all 1s. + +*/ + +void crc_reset(void) +{ + CRC_CR |= CRC_CR_RESET; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CRC Calculate. + +Writes a data word to the register, the write operation stalling until the +computation is complete. + +@param[in] data Unsigned int32. +@returns int32 Computed CRC result +*/ + +uint32_t crc_calculate(uint32_t data) +{ + CRC_DR = data; + /* Data sheet says this blocks until it's ready.... */ + return CRC_DR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief CRC Calculate of a Block of Data. + +Writes data words consecutively to the register, the write operation stalling +until the computation of each word is complete. + +@param[in] datap Unsigned int32. pointer to an array of 32 bit data words. +@param[in] size int. Size of the array. +@returns int32 Final computed CRC result +*/ + +uint32_t crc_calculate_block(uint32_t *datap, int size) +{ + int i; + + for (i = 0; i < size; i++) { + CRC_DR = datap[i]; + } + + return CRC_DR; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/crypto_common_f24.c b/libopencm3/lib/stm32/common/crypto_common_f24.c new file mode 100644 index 0000000..46cef6b --- /dev/null +++ b/libopencm3/lib/stm32/common/crypto_common_f24.c @@ -0,0 +1,175 @@ +/** @addtogroup crypto_file + * + * @brief libopencm3 STM32 Cryptographic controller + * + * @version 1.0.0 + * + * @date 17 Jun 2013 + * + * This library supports the cryptographic coprocessor system for the + * STM32 series of ARM Cortex Microcontrollers + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE) + +/** + * @brief Wait, if the Controller is busy + */ +void crypto_wait_busy(void) +{ + while (CRYP_SR & CRYP_SR_BUSY); +} + +/** + * @brief Set key value to the controller + * @param[in] keysize enum crypto_keysize Specified size of the key. + * @param[in] key uint64_t[] Key value (array of 4 items) + */ +void crypto_set_key(enum crypto_keysize keysize, uint64_t key[]) +{ + int i; + + crypto_wait_busy(); + + CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) | + (keysize << CRYP_CR_KEYSIZE_SHIFT); + + for (i = 0; i < 4; i++) { + CRYP_KR(i) = key[i]; + } +} + +/** + * @brief Set Initialization Vector + * + * @param[in] iv uint64_t[] Initialization vector (array of 4 items) + + * @note Cryptographic controller must be in disabled state + */ +void crypto_set_iv(uint64_t iv[]) +{ + int i; + + crypto_wait_busy(); + + for (i = 0; i < 4; i++) { + CRYP_IVR(i) = iv[i]; + } +} + +/** + * @brief Set the order of the data to be crypted + * + * @param[in] datatype enum crypto_datatype Specified datatype of the key. + */ +void crypto_set_datatype(enum crypto_datatype datatype) +{ + CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) | + (datatype << CRYP_CR_DATATYPE_SHIFT); +} + +/** + * @brief Set the algoritm for Encryption/decryption + * + *@param[in] mode enum crypto_mode Mode of execution + */ +void crypto_set_algorithm(enum crypto_mode mode) +{ + mode &= ~CRYP_CR_ALGOMODE_MASK; + + if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) { + /* Unroll keys for the AES encoder for the user automatically */ + + CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | + CRYP_CR_ALGOMODE_AES_PREP; + + crypto_start(); + crypto_wait_busy(); + /* module switches to DISABLE automatically */ + } + /* set algo mode */ + CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode; + + /* flush buffers */ + CRYP_CR |= CRYP_CR_FFLUSH; +} + +/** + * @brief Enable the cryptographic controller and start processing + */ +void crypto_start(void) +{ + CRYP_CR |= CRYP_CR_CRYPEN; +} + +/** + * @brief Disable the cryptographic controller and stop processing + */ + +void crypto_stop(void) +{ + CRYP_CR &= ~CRYP_CR_CRYPEN; +} + +/** + * @brief Start of encryption or decryption on data buffers + * + * This blocking method transfers input buffer of specified length to the + * cryptographic coprocessor, and instructs him to begin of ciphering or + * deciphering. It waits for data to be ready, and then fills the processed + * data to output buffer. + * + * @param[in] inp uint32_t* Input array to crypt/decrypt. + * @param[in] outp uint32_t* Output array with crypted/encrypted data. + * @param[in] length uint32_t Length of the arrays + * + * @returns uint32_t Number of written words + */ +uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length) +{ + uint32_t rd = 0, wr = 0; + + /* Transfer the data */ + while (rd != length) { + if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) { + CRYP_DIN = *inp++; + wr++; + } + + if (CRYP_SR & CRYP_SR_OFNE) { + *outp++ = CRYP_DOUT; + rd++; + } + } + + /* Wait to finish - Not needed ? */ + crypto_wait_busy(); + + return wr; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/dac_common_all.c b/libopencm3/lib/stm32/common/dac_common_all.c new file mode 100644 index 0000000..a8a0daf --- /dev/null +++ b/libopencm3/lib/stm32/common/dac_common_all.c @@ -0,0 +1,503 @@ +/** @addtogroup dac_file + +@author @htmlonly © @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net + +This library supports the Digital to Analog Conversion System in the +STM32F series of ARM Cortex Microcontrollers by ST Microelectronics. + +The DAC is present only in a limited set of devices, notably some +of the connection line, high density and XL devices. + +Two DAC channels are available, however unlike the ADC channels these +are separate DAC devices controlled by the same register block. + +The DAC is on APB1. Its clock must be enabled in RCC and depending on +specific family, the GPIO +ports set to alternate function output before it can be used. +On most families, the GPIO pins should be configured to Analog IN to +avoid parasitic consumption. +The digital output driver is disabled so the output driver mode +(push-pull/open drain) is arbitrary. + +The DAC has a holding (buffer) register and an output register from +which the analog output is derived. The holding register must be +loaded first. If triggering is enabled the output register is loaded +from the holding register after a trigger occurs. If triggering is +not enabled the holding register contents are transferred directly +to the output register. + +@note To avoid nonlinearities, do not allow outputs to range close +to zero or V_analog. + +@section dac_api_dual Dual Channel Conversion + +There are dual modes in which both DACs are used to output data +simultaneously or independently on both channels. The data must be +presented according to the formats described in the datasheets. A +convenience function @ref dac_load_data_buffer_dual is provided +for software controlled use. + +A variety of modes are available depending on whether independent +or simultaneous output is desired, and whether waveforms are to be +superimposed. Refer to the datasheets. + +If DMA is used, only enable it for one of the channels. The DMA +requests will then serve data in dual format to the data register +dedicated to dual mode. The data will then be split and loaded to the +appropriate DAC following the next trigger. There are three registers +available, one for each of the formats: 12 bit right-aligned, 12 bit +left-aligned and 8 bit right-aligned. The desired format is determined +by specifying the appropriate register to the DMA controller. + +@section dac_api_basic_ex Basic DAC handling API. + +Set the DAC's GPIO port to Analog IN. Enable the +DAC clock. Enable the DAC, set a trigger source and load the buffer +with the first value. After the DAC is triggered, load the buffer with +the next value. This example uses software triggering and added noise. +The trigger and further buffer load calls are made when data is to be +sent out. + +@code + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4); + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN); + dac_disable(CHANNEL_1); + dac_set_waveform_characteristics(DAC_CR_MAMP1_8); + dac_set_waveform_generation(DAC_CR_WAVE1_NOISE); + dac_enable(CHANNEL_1); + dac_set_trigger_source(DAC_CR_TSEL1_SW); + dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1); + .... + dac_software_trigger(CHANNEL_1); + dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1); +@endcode + +@section dac_api_dma_ex Simultaneous Dual DAC with DMA. + +This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read +16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD. +Both DAC channels are enabled, and both triggers are set to the same timer +2 input as required for simultaneous operation. DMA is enabled for DAC channel +1 only to ensure that only one DMA request is generated. + +@code + dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT); + dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT); + dma_set_read_from_memory(DMA2,DMA_CHANNEL3); + dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD); + dma_enable_channel(DMA2,DMA_CHANNEL3); + ... + dac_trigger_enable(CHANNEL_D); + dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2); + dac_dma_enable(CHANNEL_1); + dac_enable(CHANNEL_D); +@endcode + +LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +#define MASK8 0xFF +#define MASK12 0xFFF + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Enable. + +Enable a digital to analog converter channel. After setting this enable, the +DAC requires a twakeup time typically around 10 microseconds before +it actually wakes up. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_enable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR |= DAC_CR_EN1; + break; + case CHANNEL_2: + DAC_CR |= DAC_CR_EN2; + break; + case CHANNEL_D: + DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Disable. + +Disable a digital to analog converter channel. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_disable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR &= ~DAC_CR_EN1; + break; + case CHANNEL_2: + DAC_CR &= ~DAC_CR_EN2; + break; + case CHANNEL_D: + DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Output Buffer Enable. + +Enable a digital to analog converter channel output drive buffer. This is an +optional amplifying buffer that provides additional drive for the output +signal. The buffer is enabled by default after a reset and needs to be +explicitly disabled if required. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_buffer_enable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR &= ~DAC_CR_BOFF1; + break; + case CHANNEL_2: + DAC_CR &= ~DAC_CR_BOFF2; + break; + case CHANNEL_D: + DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2); + break; + } +} +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Output Buffer Disable. + +Disable a digital to analog converter channel output drive buffer. Disabling +this will reduce power consumption slightly and will increase the output +impedance of the DAC. The buffers are enabled by default after a reset. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_buffer_disable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR |= DAC_CR_BOFF1; + break; + case CHANNEL_2: + DAC_CR |= DAC_CR_BOFF2; + break; + case CHANNEL_D: + DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2); + break; + } +} +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel DMA Enable. + +Enable a digital to analog converter channel DMA mode (connected to DMA2 channel +3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is +generated following an external trigger. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_dma_enable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR |= DAC_CR_DMAEN1; + break; + case CHANNEL_2: + DAC_CR |= DAC_CR_DMAEN2; + break; + case CHANNEL_D: + DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel DMA Disable. + +Disable a digital to analog converter channel DMA mode. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_dma_disable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR &= ~DAC_CR_DMAEN1; + break; + case CHANNEL_2: + DAC_CR &= ~DAC_CR_DMAEN2; + break; + case CHANNEL_D: + DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Trigger Enable. + +Enable a digital to analog converter channel external trigger mode. This allows +an external trigger to initiate register transfers from the buffer register to +the DAC output register, followed by a DMA transfer to the buffer register if +DMA is enabled. The trigger source must also be selected. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_trigger_enable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR |= DAC_CR_TEN1; + break; + case CHANNEL_2: + DAC_CR |= DAC_CR_TEN2; + break; + case CHANNEL_D: + DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DAC Channel Trigger Disable. + +Disable a digital to analog converter channel external trigger. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_trigger_disable(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR &= ~DAC_CR_TEN1; + break; + case CHANNEL_2: + DAC_CR &= ~DAC_CR_TEN2; + break; + case CHANNEL_D: + DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set DAC Channel Trigger Source. + +Sets the digital to analog converter trigger source, which can be taken from +various timers, an external trigger or a software trigger. + +@param[in] dac_trig_src uint32_t. Taken from @ref dac_trig2_sel or @ref +dac_trig1_sel or a logical OR of one of each of these to set both channels +simultaneously. +*/ + +void dac_set_trigger_source(uint32_t dac_trig_src) +{ + DAC_CR |= dac_trig_src; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable and Set DAC Channel Waveform Generation. + +Enable the digital to analog converter waveform generation as either +pseudo-random noise or triangular wave. These signals are superimposed on +existing output values in the DAC output registers. + +@note The DAC trigger must be enabled for this to work. + +@param[in] dac_wave_ens uint32_t. Taken from @ref dac_wave1_en or @ref +dac_wave2_en or a logical OR of one of each of these to set both channels +simultaneously. +*/ + +void dac_set_waveform_generation(uint32_t dac_wave_ens) +{ + DAC_CR |= dac_wave_ens; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable DAC Channel Waveform Generation. + +Disable a digital to analog converter channel superimposed waveform generation. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_disable_waveform_generation(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_CR &= ~DAC_CR_WAVE1_DIS; + break; + case CHANNEL_2: + DAC_CR &= ~DAC_CR_WAVE2_DIS; + break; + case CHANNEL_D: + DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude. + +Sets the digital to analog converter superimposed waveform generation +characteristics. @li If the noise generation mode is set, this sets the length +of the PRBS sequence and hence the amplitude of the output noise signal. +Default setting is length 1. @li If the triangle wave generation mode is set, +this sets the amplitude of the output signal as 2^(n)-1 where n is the +parameter value. Default setting is 1. + +@note High amplitude levels of these waveforms can overload the DAC and distort +the signal output. +@note This must be called before enabling the DAC as the settings will then +become read-only. +@note The DAC trigger must be enabled for this to work. + +@param[in] dac_mamp uint32_t. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a +logical OR of one of each of these to set both channels simultaneously. +*/ + +void dac_set_waveform_characteristics(uint32_t dac_mamp) +{ + DAC_CR |= dac_mamp; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Load DAC Data Register. + +Loads the appropriate digital to analog converter data register with 12 or 8 bit +data to be converted on a channel. The data can be aligned as follows: +@li right-aligned 8 bit data in bits 0-7 +@li right-aligned 12 bit data in bits 0-11 +@li left aligned 12 bit data in bits 4-15 + +@param[in] dac_data uint16_t with appropriate alignment. +@param[in] dac_data_format enum ::data_align. Alignment and size. +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_load_data_buffer_single(uint16_t dac_data, data_align dac_data_format, + data_channel dac_channel) +{ + if (dac_channel == CHANNEL_1) { + switch (dac_data_format) { + case RIGHT8: + DAC_DHR8R1 = dac_data; + break; + case RIGHT12: + DAC_DHR12R1 = dac_data; + break; + case LEFT12: + DAC_DHR12L1 = dac_data; + break; + } + } else if (dac_channel == CHANNEL_2) { + switch (dac_data_format) { + case RIGHT8: + DAC_DHR8R2 = dac_data; + break; + case RIGHT12: + DAC_DHR12R2 = dac_data; + break; + case LEFT12: + DAC_DHR12L2 = dac_data; + break; + } + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Load DAC Dual Data Register. + +Loads the appropriate digital to analog converter dual data register with 12 or +8 bit data to be converted for both channels. This allows high bandwidth +simultaneous or independent analog output. The data in both channels are aligned +identically. + +@param[in] dac_data1 uint16_t for channel 1 with appropriate alignment. +@param[in] dac_data2 uint16_t for channel 2 with appropriate alignment. +@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or +12 bit. +*/ + +void dac_load_data_buffer_dual(uint16_t dac_data1, uint16_t dac_data2, + data_align dac_data_format) +{ + switch (dac_data_format) { + case RIGHT8: + DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8)); + break; + case RIGHT12: + DAC_DHR12RD = ((dac_data1 & MASK12) | + ((dac_data2 & MASK12) << 16)); + break; + case LEFT12: + DAC_DHR12LD = ((dac_data1 & MASK12) | + ((dac_data2 & MASK12) << 16)); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Trigger the DAC by a Software Trigger. + +If the trigger source is set to be a software trigger, cause a trigger to occur. +The trigger is cleared by hardware after conversion. + +@param[in] dac_channel enum ::data_channel. +*/ + +void dac_software_trigger(data_channel dac_channel) +{ + switch (dac_channel) { + case CHANNEL_1: + DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1; + break; + case CHANNEL_2: + DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2; + break; + case CHANNEL_D: + DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2); + break; + } +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/dma_common_f24.c b/libopencm3/lib/stm32/common/dma_common_f24.c new file mode 100644 index 0000000..6b65563 --- /dev/null +++ b/libopencm3/lib/stm32/common/dma_common_f24.c @@ -0,0 +1,794 @@ +/** @addtogroup dma_file + +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +This library supports the DMA Control System in the STM32F2 and STM32F4 +series of ARM Cortex Microcontrollers by ST Microelectronics. + +Up to two DMA controllers are supported each with 8 streams, and each stream +having up to 8 channels hardware dedicated to various peripheral DMA signals. + +DMA transfers can be configured to occur between peripheral and memory in +either direction, and memory to memory. Peripheral to peripheral transfer +is not supported. Circular mode transfers are also supported in transfers +involving a peripheral. An arbiter is provided to resolve priority DMA +requests. Transfers can be made with 8, 16 or 32 bit words. + +Each stream has access to a 4 word deep FIFO and can use double buffering +by means of two memory pointers. When using the FIFO it is possible to +configure transfers to occur in indivisible bursts. + +It is also possible to select a peripheral instead of the DMA controller to +control the flow of data. This limits the functionality but is useful when the +number of transfers is unknown. + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Reset + +The specified stream is disabled and configuration registers are cleared. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_stream_reset(uint32_t dma, uint8_t stream) +{ +/* Disable stream (must be done before register is otherwise changed). */ + DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; +/* Reset all config bits. */ + DMA_SCR(dma, stream) = 0; +/* Reset data transfer number. */ + DMA_SNDTR(dma, stream) = 0; +/* Reset peripheral and memory addresses. */ + DMA_SPAR(dma, stream) = 0; + DMA_SM0AR(dma, stream) = 0; + DMA_SM1AR(dma, stream) = 0; +/* This is the default setting */ + DMA_SFCR(dma, stream) = 0x21; +/* Reset all stream interrupt flags using the interrupt flag clear register. */ + uint32_t mask = DMA_ISR_MASK(stream); + if (stream < 4) { + DMA_LIFCR(dma) |= mask; + } else { + DMA_HIFCR(dma) |= mask; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Clear Interrupt Flag + +The interrupt flag for the stream is cleared. More than one interrupt for the +same stream may be cleared by using the bitwise OR of the interrupt flags. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] interrupts unsigned int32. Bitwise OR of interrupt numbers: @ref +dma_if_offset +*/ + +void dma_clear_interrupt_flags(uint32_t dma, uint8_t stream, + uint32_t interrupts) +{ + /* Get offset to interrupt flag location in stream field */ + uint32_t flags = (interrupts << DMA_ISR_OFFSET(stream)); + /* First four streams are in low register. Flag clear must be set then + * reset. + */ + if (stream < 4) { + DMA_LIFCR(dma) = flags; + } else { + DMA_HIFCR(dma) = flags; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Read Interrupt Flag + +The interrupt flag for the stream is returned. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset +@returns bool interrupt flag is set. +*/ + +bool dma_get_interrupt_flag(uint32_t dma, uint8_t stream, uint32_t interrupt) +{ + /* get offset to interrupt flag location in stream field. Assumes + * stream and interrupt parameters are integers. + */ + uint32_t flag = (interrupt << DMA_ISR_OFFSET(stream)); + /* First four streams are in low register */ + if (stream < 4) { + return ((DMA_LISR(dma) & flag) > 0); + } else { + return ((DMA_HISR(dma) & flag) > 0); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Transfer Direction + +Set peripheral to memory, memory to peripheral or memory to memory. If memory +to memory mode is selected, circular mode and double buffer modes are disabled. +Ensure that these modes are not enabled at a later time. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] direction unsigned int32. Data transfer direction @ref dma_st_dir +*/ + +void dma_set_transfer_mode(uint32_t dma, uint8_t stream, uint32_t direction) +{ + uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_DIR_MASK); + /* Disable circular and double buffer modes if memory to memory + * transfers are in effect. (Direct Mode is automatically disabled by + * hardware) + */ + if (direction == DMA_SxCR_DIR_MEM_TO_MEM) { + reg32 &= ~(DMA_SxCR_CIRC | DMA_SxCR_DBM); + } + + DMA_SCR(dma, stream) = (reg32 | direction); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Priority + +Stream Priority has four levels: low to very high. This has precedence over the +hardware priority. In the event of equal software priority the lower numbered +stream has priority. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] prio unsigned int32. Priority level @ref dma_st_pri. +*/ + +void dma_set_priority(uint32_t dma, uint8_t stream, uint32_t prio) +{ + DMA_SCR(dma, stream) &= ~(DMA_SxCR_PL_MASK); + DMA_SCR(dma, stream) |= prio; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Memory Word Width + +Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for +alignment information if the source and destination widths do not match. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] mem_size unsigned int32. Memory word width @ref dma_st_memwidth. +*/ + +void dma_set_memory_size(uint32_t dma, uint8_t stream, uint32_t mem_size) +{ + DMA_SCR(dma, stream) &= ~(DMA_SxCR_MSIZE_MASK); + DMA_SCR(dma, stream) |= mem_size; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Peripheral Word Width + +Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet +for alignment information if the source and destination widths do not match, or +if the peripheral does not support byte or half-word writes. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] peripheral_size unsigned int32. Peripheral word width @ref +dma_st_perwidth. +*/ + +void dma_set_peripheral_size(uint32_t dma, uint8_t stream, + uint32_t peripheral_size) +{ + DMA_SCR(dma, stream) &= ~(DMA_SxCR_PSIZE_MASK); + DMA_SCR(dma, stream) |= peripheral_size; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Memory Increment after Transfer + +Following each transfer the current memory address is incremented by +1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The +value held by the base memory address register is unchanged. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_memory_increment_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= DMA_SxCR_MINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Memory Increment after Transfer + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_memory_increment_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_MINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Variable Sized Peripheral Increment after Transfer + +Following each transfer the current peripheral address is incremented by +1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The +value held by the base peripheral address register is unchanged. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t stream) +{ + uint32_t reg32 = (DMA_SCR(dma, stream) | DMA_SxCR_PINC); + DMA_SCR(dma, stream) = (reg32 & ~DMA_SxCR_PINCOS); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Peripheral Increment after Transfer + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_PINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Fixed Sized Peripheral Increment after Transfer + +Following each transfer the current peripheral address is incremented by +4 regardless of the data size. The value held by the base peripheral address +register is unchanged. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_fixed_peripheral_increment_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= (DMA_SxCR_PINC | DMA_SxCR_PINCOS); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Memory Circular Mode + +After the number of bytes/words to be transferred has been completed, the +original transfer block size, memory and peripheral base addresses are +reloaded and the process repeats. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@note This cannot be used with memory to memory mode. It is disabled +automatically if the peripheral is selected as the flow controller. +It is enabled automatically if double buffered mode is selected. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_circular_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= DMA_SxCR_CIRC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Channel Select + +Associate an input channel to the stream. Not every channel is allocated to a +hardware DMA request signal. The allocations for each stream are given in the +STM32F4 Reference Manual. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] channel unsigned int8. Channel selection @ref dma_ch_sel +*/ + +void dma_channel_select(uint32_t dma, uint8_t stream, uint32_t channel) +{ + DMA_SCR(dma, stream) |= channel; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Memory Burst Configuration + +Set the memory burst type to none, 4 8 or 16 word length. This is forced to none +if direct mode is used. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] burst unsigned int8. Memory Burst selection @ref dma_mburst +*/ + +void dma_set_memory_burst(uint32_t dma, uint8_t stream, uint32_t burst) +{ + uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_MBURST_MASK); + DMA_SCR(dma, stream) = (reg32 | burst); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Peripheral Burst Configuration + +Set the memory burst type to none, 4 8 or 16 word length. This is forced to none +if direct mode is used. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] burst unsigned int8. Peripheral Burst selection @ref dma_pburst +*/ + +void dma_set_peripheral_burst(uint32_t dma, uint8_t stream, uint32_t burst) +{ + uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_PBURST_MASK); + DMA_SCR(dma, stream) = (reg32 | burst); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Initial Target Memory + +In double buffered mode, set the target memory (M0 or M1) to be used for the +first transfer. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] memory unsigned int8. Initial memory pointer to use: 0 or 1 +*/ + +void dma_set_initial_target(uint32_t dma, uint8_t stream, uint8_t memory) +{ + uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_CT); + if (memory == 1) { + reg32 |= DMA_SxCR_CT; + } + + DMA_SCR(dma, stream) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Read Current Memory Target + +In double buffer mode, return the current memory target (M0 or M1). It is +possible to update the memory pointer in the register that is not +currently in use. An attempt to change the register currently in use will cause +the stream to be disabled and the transfer error flag to be set. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@returns unsigned int8. Memory buffer in use: 0 or 1 +*/ + +uint8_t dma_get_target(uint32_t dma, uint8_t stream) +{ + if (DMA_SCR(dma, stream) & DMA_SxCR_CT) { + return 1; + } + + return 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Double Buffer Mode + +Double buffer mode is used for memory to/from peripheral transfers only, and in +circular mode which is automatically enabled. Two memory buffers must be +established with pointers stored in the memory pointer registers. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@note This cannot be used with memory to memory mode. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_double_buffer_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= DMA_SxCR_DBM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable Double Buffer Mode + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_double_buffer_mode(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_DBM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set Peripheral Flow Control + +Set the peripheral to control DMA flow. Useful when the number of transfers is +unknown. This is forced off when memory to memory mode is selected. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_set_peripheral_flow_control(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= DMA_SxCR_PFCTRL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set DMA Flow Control + +Set the DMA controller to control DMA flow. This is the default. + +Ensure that the stream is disabled otherwise the setting will not be changed. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_set_dma_flow_control(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_PFCTRL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Interrupt on Transfer Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t stream) +{ + dma_clear_interrupt_flags(dma, stream, DMA_TEIF); + DMA_SCR(dma, stream) |= DMA_SxCR_TEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable Interrupt on Transfer Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_TEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Interrupt on Transfer Half Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t stream) +{ + dma_clear_interrupt_flags(dma, stream, DMA_HTIF); + DMA_SCR(dma, stream) |= DMA_SxCR_HTIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable Interrupt on Transfer Half Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_HTIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Interrupt on Transfer Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t stream) +{ + dma_clear_interrupt_flags(dma, stream, DMA_TCIF); + DMA_SCR(dma, stream) |= DMA_SxCR_TCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable Interrupt on Transfer Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_TCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable Interrupt on Direct Mode Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream) +{ + dma_clear_interrupt_flags(dma, stream, DMA_DMEIF); + DMA_SCR(dma, stream) |= DMA_SxCR_DMEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable Interrupt on Direct Mode Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_DMEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Enable Interrupt on FIFO Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_fifo_error_interrupt(uint32_t dma, uint8_t stream) +{ + dma_clear_interrupt_flags(dma, stream, DMA_FEIF); + DMA_SFCR(dma, stream) |= DMA_SxFCR_FEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Disable Interrupt on FIFO Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_fifo_error_interrupt(uint32_t dma, uint8_t stream) +{ + DMA_SFCR(dma, stream) &= ~DMA_SxFCR_FEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Get FIFO Status + +Status of FIFO (empty. full or partial filled states) is returned. This has no +meaning if direct mode is enabled (as the FIFO is not used). + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@returns uint32_t FIFO Status @ref dma_fifo_status +*/ + +uint32_t dma_fifo_status(uint32_t dma, uint8_t stream) +{ + return DMA_SFCR(dma, stream) & DMA_SxFCR_FS_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Enable Direct Mode + +Direct mode is the default. Data is transferred as soon as a DMA request is +received. The FIFO is not used. This must not be set when memory to memory +mode is selected. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_direct_mode(uint32_t dma, uint8_t stream) +{ + DMA_SFCR(dma, stream) &= ~DMA_SxFCR_DMDIS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Enable FIFO Mode + +Data is transferred via a FIFO. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_fifo_mode(uint32_t dma, uint8_t stream) +{ + DMA_SFCR(dma, stream) |= DMA_SxFCR_DMDIS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Set FIFO Threshold + +This is the filled level at which data is transferred out of the FIFO to the +destination. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] threshold unsigned int8. Threshold setting @ref dma_fifo_thresh +*/ + +void dma_set_fifo_threshold(uint32_t dma, uint8_t stream, uint32_t threshold) +{ + uint32_t reg32 = (DMA_SFCR(dma, stream) & ~DMA_SxFCR_FTH_MASK); + DMA_SFCR(dma, stream) = (reg32 | threshold); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Enable + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_enable_stream(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) |= DMA_SxCR_EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Disable + +@note The DMA stream registers retain their values when the stream is disabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +*/ + +void dma_disable_stream(uint32_t dma, uint8_t stream) +{ + DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set the Peripheral Address + +Set the address of the peripheral register to or from which data is to be +transferred. Refer to the documentation for the specific peripheral. + +@note The DMA stream must be disabled before setting this address. This function +has no effect if the stream is enabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] address unsigned int32. Peripheral Address. +*/ + +void dma_set_peripheral_address(uint32_t dma, uint8_t stream, uint32_t address) +{ + if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) { + DMA_SPAR(dma, stream) = (uint32_t *) address; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set the Base Memory Address 0 + +Set the address pointer to the memory location for DMA transfers. The DMA stream +must normally be disabled before setting this address, however it is possible +to change this in double buffer mode when the current target is memory area 1 +(see @ref dma_get_target). + +This is the default base memory address used in direct mode. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] address unsigned int32. Memory Initial Address. +*/ + +void dma_set_memory_address(uint32_t dma, uint8_t stream, uint32_t address) +{ + uint32_t reg32 = DMA_SCR(dma, stream); + if (!(reg32 & DMA_SxCR_EN) || + ((reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) { + DMA_SM0AR(dma, stream) = (uint32_t *) address; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set the Base Memory Address 1 + +Set the address pointer to the memory location for DMA transfers. The DMA stream +must normally be disabled before setting this address, however it is possible +to change this in double buffer mode when the current target is memory area 0 +(see @ref dma_get_target). + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] address unsigned int32. Memory Initial Address. +*/ + +void dma_set_memory_address_1(uint32_t dma, uint8_t stream, uint32_t address) +{ + uint32_t reg32 = DMA_SCR(dma, stream); + if (!(reg32 & DMA_SxCR_EN) || + (!(reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) { + DMA_SM1AR(dma, stream) = (uint32_t *) address; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Stream Set the Transfer Block Size + +@note The DMA stream must be disabled before setting this count value. The count +is not changed if the stream is enabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] stream unsigned int8. Stream number: @ref dma_st_number +@param[in] number unsigned int16. Number of data words to transfer (65535 +maximum). +*/ + +void dma_set_number_of_data(uint32_t dma, uint8_t stream, uint16_t number) +{ + DMA_SNDTR(dma, stream) = number; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/dma_common_l1f013.c b/libopencm3/lib/stm32/common/dma_common_l1f013.c new file mode 100644 index 0000000..d705964 --- /dev/null +++ b/libopencm3/lib/stm32/common/dma_common_l1f013.c @@ -0,0 +1,435 @@ +/** @addtogroup dma_file + +@author @htmlonly © @endhtmlonly 2010 Thomas Otto + +This library supports the DMA Control System in the STM32 series of ARM Cortex +Microcontrollers by ST Microelectronics. + +Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to +the first DMA controller and 5 to the second. Each channel is connected to +between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement. + +DMA transfers can be configured to occur between peripheral and memory in +any combination including memory to memory. Circular mode transfers are +also supported in transfers involving a peripheral. An arbiter is provided +to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit +words. + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Reset + +The channel is disabled and configuration registers are cleared. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_channel_reset(uint32_t dma, uint8_t channel) +{ + /* Disable channel and reset config bits. */ + DMA_CCR(dma, channel) = 0; + /* Reset data transfer number. */ + DMA_CNDTR(dma, channel) = 0; + /* Reset peripheral address. */ + DMA_CPAR(dma, channel) = 0; + /* Reset memory address. */ + DMA_CMAR(dma, channel) = 0; + /* Reset interrupt flags. */ + DMA_IFCR(dma) |= DMA_IFCR_CIF(channel); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Clear Interrupt Flag + +The interrupt flag for the channel is cleared. More than one interrupt for the +same channel may be cleared by using the logical OR of the interrupt flags. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: @ref dma_ch +@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref +dma_if_offset +*/ + +void dma_clear_interrupt_flags(uint32_t dma, uint8_t channel, + uint32_t interrupts) +{ +/* Get offset to interrupt flag location in channel field */ + uint32_t flags = (interrupts << DMA_FLAG_OFFSET(channel)); + DMA_IFCR(dma) = flags; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Read Interrupt Flag + +The interrupt flag for the channel is returned. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: @ref dma_ch +@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset +@returns bool interrupt flag is set. +*/ + +bool dma_get_interrupt_flag(uint32_t dma, uint8_t channel, uint32_t interrupt) +{ +/* get offset to interrupt flag location in channel field. */ + uint32_t flag = (interrupt << DMA_FLAG_OFFSET(channel)); + return ((DMA_ISR(dma) & flag) > 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Memory to Memory Transfers + +Memory to memory transfers do not require a trigger to activate each transfer. +Transfers begin immediately the channel has been enabled, and proceed without +intervention. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_mem2mem_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM; + DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set Priority + +Channel Priority has four levels: low to very high. This has precedence over the +hardware priority. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] prio unsigned int32. Priority level @ref dma_ch_pri. +*/ + +void dma_set_priority(uint32_t dma, uint8_t channel, uint32_t prio) +{ + DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK); + DMA_CCR(dma, channel) |= prio; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set Memory Word Width + +Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for +alignment information if the source and destination widths do not match. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth. +*/ + +void dma_set_memory_size(uint32_t dma, uint8_t channel, uint32_t mem_size) +{ + + DMA_CCR(dma, channel) &= ~(DMA_CCR_MSIZE_MASK); + DMA_CCR(dma, channel) |= mem_size; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set Peripheral Word Width + +Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet +for alignment information if the source and destination widths do not match, or +if the peripheral does not support byte or half-word writes. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] peripheral_size unsigned int32. Peripheral word width @ref +dma_ch_perwidth. +*/ + +void dma_set_peripheral_size(uint32_t dma, uint8_t channel, + uint32_t peripheral_size) +{ + DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK); + DMA_CCR(dma, channel) |= peripheral_size; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Memory Increment after Transfer + +Following each transfer the current memory address is incremented by +1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The +value held by the base memory address register is unchanged. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_memory_increment_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_MINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Memory Increment after Transfer + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_memory_increment_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_MINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Peripheral Increment after Transfer + +Following each transfer the current peripheral address is incremented by +1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The +value held by the base peripheral address register is unchanged. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_PINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Peripheral Increment after Transfer + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_PINC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Memory Circular Mode + +After the number of bytes/words to be transferred has been completed, the +original transfer block size, memory and peripheral base addresses are +reloaded and the process repeats. + +@note This cannot be used with memory to memory mode, which is explictly +disabled here. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_circular_mode(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_CIRC; + DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Transfers from a Peripheral + +The data direction is set to read from a peripheral. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_set_read_from_peripheral(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_DIR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Transfers from Memory + +The data direction is set to read from memory. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_set_read_from_memory(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_DIR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Interrupt on Transfer Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_TEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Interrupt on Transfer Error + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Interrupt on Transfer Half Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_HTIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Interrupt on Transfer Half Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Interrupt on Transfer Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_TCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Interrupt on Transfer Complete + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_enable_channel(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) |= DMA_CCR_EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable + +@note The DMA channel registers retain their values when the channel is +disabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_channel(uint32_t dma, uint8_t channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set the Peripheral Address + +Set the address of the peripheral register to or from which data is to be +transferred. Refer to the documentation for the specific peripheral. + +@note The DMA channel must be disabled before setting this address. This +function has no effect if the channel is enabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] address unsigned int32. Peripheral Address. +*/ + +void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address) +{ + if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) { + DMA_CPAR(dma, channel) = (uint32_t) address; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set the Base Memory Address + +@note The DMA channel must be disabled before setting this address. This +function has no effect if the channel is enabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] address unsigned int32. Memory Initial Address. +*/ + +void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address) +{ + if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) { + DMA_CMAR(dma, channel) = (uint32_t) address; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief DMA Channel Set the Transfer Block Size + +@note The DMA channel must be disabled before setting this count value. The +count is not changed if the channel is enabled. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +@param[in] number unsigned int16. Number of data words to transfer (65535 +maximum). +*/ + +void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number) +{ + DMA_CNDTR(dma, channel) = number; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/exti_common_all.c b/libopencm3/lib/stm32/common/exti_common_all.c new file mode 100644 index 0000000..f7b0d0c --- /dev/null +++ b/libopencm3/lib/stm32/common/exti_common_all.c @@ -0,0 +1,154 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Mark Butler + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + * This provides the code for the "next gen" EXTI block provided in F2/F4/L1 + * devices. (differences only in the source selection) + */ +/**@{*/ + + +#include +#include +#if !defined(AFIO_BASE) +# include +#endif + +void exti_set_trigger(uint32_t extis, enum exti_trigger_type trig) +{ + switch (trig) { + case EXTI_TRIGGER_RISING: + EXTI_RTSR |= extis; + EXTI_FTSR &= ~extis; + break; + case EXTI_TRIGGER_FALLING: + EXTI_RTSR &= ~extis; + EXTI_FTSR |= extis; + break; + case EXTI_TRIGGER_BOTH: + EXTI_RTSR |= extis; + EXTI_FTSR |= extis; + break; + } +} + +void exti_enable_request(uint32_t extis) +{ + /* Enable interrupts. */ + EXTI_IMR |= extis; + + /* Enable events. */ + EXTI_EMR |= extis; +} + +void exti_disable_request(uint32_t extis) +{ + /* Disable interrupts. */ + EXTI_IMR &= ~extis; + + /* Disable events. */ + EXTI_EMR &= ~extis; +} + +/* + * Reset the interrupt request by writing a 1 to the corresponding + * pending bit register. + */ +void exti_reset_request(uint32_t extis) +{ + EXTI_PR = extis; +} + +/* + * Check the flag of a given EXTI interrupt. + * */ +uint32_t exti_get_flag_status(uint32_t exti) +{ + return EXTI_PR & exti; +} + +/* + * Remap an external interrupt line to the corresponding pin on the + * specified GPIO port. + * + * TODO: This could be rewritten in fewer lines of code. + */ +void exti_select_source(uint32_t exti, uint32_t gpioport) +{ + uint32_t line; + for (line = 0; line < 16; line++) { + if (!(exti & (1 << line))) { + continue; + } + + uint32_t bits = 0, mask = 0x0F; + + switch (gpioport) { + case GPIOA: + bits = 0; + break; + case GPIOB: + bits = 1; + break; + case GPIOC: + bits = 2; + break; + case GPIOD: + bits = 3; + break; +#if defined(GPIOE) && defined(GPIO_PORT_E_BASE) + case GPIOE: + bits = 4; + break; +#endif +#if defined(GPIOF) && defined(GPIO_PORT_F_BASE) + case GPIOF: + bits = 5; + break; +#endif +#if defined(GPIOG) && defined(GPIO_PORT_G_BASE) + case GPIOG: + bits = 6; + break; +#endif +#if defined(GPIOH) && defined(GPIO_PORT_H_BASE) + case GPIOH: + bits = 7; + break; +#endif +#if defined(GPIOI) && defined(GPIO_PORT_I_BASE) + case GPIOI: + bits = 8; + break; +#endif + } + + uint8_t shift = (uint8_t)(4 * (line % 4)); + uint32_t reg = line / 4; + bits <<= shift; + mask <<= shift; + +#if defined(AFIO_BASE) + AFIO_EXTICR(reg) = (AFIO_EXTICR(reg) & ~mask) | bits; +#else + SYSCFG_EXTICR(reg) = (SYSCFG_EXTICR(reg) & ~mask) | bits; +#endif + }; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/flash_common_f01.c b/libopencm3/lib/stm32/common/flash_common_f01.c new file mode 100644 index 0000000..65f64bd --- /dev/null +++ b/libopencm3/lib/stm32/common/flash_common_f01.c @@ -0,0 +1,235 @@ +/** @addtogroup flash_file + * + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the FLASH Prefetch Buffer + +This buffer is used for instruction fetches and is enabled by default after +reset. + +Note carefully the clock restrictions under which the prefetch buffer may be +enabled or disabled. Changes are normally made while the clock is running in +the power-on low frequency mode before being set to a higher speed mode. +See the reference manual for details. +*/ + +void flash_prefetch_buffer_enable(void) +{ + FLASH_ACR |= FLASH_ACR_PRFTBE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the FLASH Prefetch Buffer + +Note carefully the clock restrictions under which the prefetch buffer may be +set to disabled. See the reference manual for details. +*/ + +void flash_prefetch_buffer_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_PRFTBE; +} +/*---------------------------------------------------------------------------*/ +/** @brief Set the Number of Wait States + +Used to match the system clock to the FLASH memory access time. See the +reference manual for more information on clock speed ranges for each wait state. +The latency must be changed to the appropriate value before any increase +in clock speed, or after any decrease in clock speed. + +@param[in] uint32_t ws: values from @ref flash_latency. +*/ + +void flash_set_ws(uint32_t ws) +{ + FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY) | ws; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Flash Program and Erase Controller + +This enables write access to the Flash memory. It is locked by default on +reset. +*/ + +void flash_unlock(void) +{ + /* Clear the unlock state. */ + FLASH_CR |= FLASH_CR_LOCK; + + /* Authorize the FPEC access. */ + FLASH_KEYR = FLASH_KEYR_KEY1; + FLASH_KEYR = FLASH_KEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Flash Program and Erase Controller + +Used to prevent spurious writes to FLASH. +*/ + +void flash_lock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Error Status Flag + +*/ + +void flash_clear_pgerr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the End of Operation Status Flag + +*/ + +void flash_clear_eop_flag(void) +{ + FLASH_SR |= FLASH_SR_EOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Write Protect Error Status Flag + +*/ + +void flash_clear_wrprterr_flag(void) +{ + FLASH_SR |= FLASH_SR_WRPRTERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Busy Status Flag + +*/ + +void flash_clear_bsy_flag(void) +{ + FLASH_SR &= ~FLASH_SR_BSY; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Wait until Last Operation has Ended + +This loops indefinitely until an operation (write or erase) has completed by +testing the busy flag. +*/ + +void flash_wait_for_last_operation(void) +{ + while ((flash_get_status_flags() & FLASH_SR_BSY) == FLASH_SR_BSY); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a 32 bit Word to FLASH + +This performs all operations necessary to program a 32 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +Status bit polling is used to detect end of operation. + +@param[in] uint32_t address. Full address of flash word to be programmed. +@param[in] uint32_t data. +*/ + +void flash_program_word(uint32_t address, uint32_t data) +{ + flash_program_half_word(address,(uint16_t)data); + flash_program_half_word(address+2,(uint16_t)(data>>16)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Option Byte Access + +This enables write access to the option bytes. It is locked by default on +reset. +*/ + +void flash_unlock_option_bytes(void) +{ + /* F1 uses same keys for flash and option */ + FLASH_OPTKEYR = FLASH_KEYR_KEY1; + FLASH_OPTKEYR = FLASH_KEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase All Option Bytes + +This performs all operations necessary to erase the option bytes. These must +first be fully erased before attempting to program them, therefore it is +recommended to check these after an erase attempt. +*/ + +void flash_erase_option_bytes(void) +{ + flash_wait_for_last_operation(); + + if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) { + flash_unlock_option_bytes(); + } + + FLASH_CR |= FLASH_CR_OPTER; /* Enable option byte erase. */ + FLASH_CR |= FLASH_CR_STRT; + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_OPTER; /* Disable option byte erase. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program the Option Bytes + +This performs all operations necessary to program the option bytes. +The write protect error flag should be checked separately for the event that +an option byte had not been properly erased before calling this function. + +Only the lower 8 bits of the data is significant. + +@param[in] uint32_t address. Address of option byte from @ref flash_options. +@param[in] uint16_t data. +*/ + +void flash_program_option_bytes(uint32_t address, uint16_t data) +{ + flash_wait_for_last_operation(); + + if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) { + flash_unlock_option_bytes(); + } + + FLASH_CR |= FLASH_CR_OPTPG; /* Enable option byte programming. */ + MMIO16(address) = data; + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_OPTPG; /* Disable option byte programming. */ +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/flash_common_f234.c b/libopencm3/lib/stm32/common/flash_common_f234.c new file mode 100644 index 0000000..1d99566 --- /dev/null +++ b/libopencm3/lib/stm32/common/flash_common_f234.c @@ -0,0 +1,121 @@ +/** @addtogroup flash_file + * + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Number of Wait States + +Used to match the system clock to the FLASH memory access time. See the +programming manual for more information on clock speed ranges. The latency must +be changed to the appropriate value before any increase in clock +speed, or after any decrease in clock speed. + +@param[in] uint32_t ws: values from @ref flash_latency. +*/ + +void flash_set_ws(uint32_t ws) +{ + uint32_t reg32; + + reg32 = FLASH_ACR; + reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2)); + reg32 |= ws; + FLASH_ACR = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Flash Program and Erase Controller + +This enables write access to the Flash memory. It is locked by default on +reset. +*/ + +void flash_unlock(void) +{ + /* Clear the unlock sequence state. */ + FLASH_CR |= FLASH_CR_LOCK; + + /* Authorize the FPEC access. */ + FLASH_KEYR = FLASH_KEYR_KEY1; + FLASH_KEYR = FLASH_KEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Flash Program and Erase Controller + +Used to prevent spurious writes to FLASH. +*/ + +void flash_lock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Error Status Flag + +*/ + +void flash_clear_pgperr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGPERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the End of Operation Status Flag + +*/ + +void flash_clear_eop_flag(void) +{ + FLASH_SR |= FLASH_SR_EOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Busy Status Flag + +*/ + +void flash_clear_bsy_flag(void) +{ + FLASH_SR &= ~FLASH_SR_BSY; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief Wait until Last Operation has Ended + +This loops indefinitely until an operation (write or erase) has completed by +testing the busy flag. +*/ + +void flash_wait_for_last_operation(void) +{ + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY); +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/flash_common_f24.c b/libopencm3/lib/stm32/common/flash_common_f24.c new file mode 100644 index 0000000..03883fb --- /dev/null +++ b/libopencm3/lib/stm32/common/flash_common_f24.c @@ -0,0 +1,416 @@ +/** @addtogroup flash_file + * + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Program Parallelism Size + +Set the programming word width. Note carefully the power supply voltage +restrictions under which the different word sizes may be used. See the +programming manual for more information. + +@param psize: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit) +*/ + +static inline void flash_set_program_size(uint32_t psize) +{ + FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8); + FLASH_CR |= psize; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the Data Cache + +*/ + +void flash_dcache_enable(void) +{ + FLASH_ACR |= FLASH_ACR_DCE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the Data Cache + +*/ + +void flash_dcache_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_DCE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the Instruction Cache + +*/ + +void flash_icache_enable(void) +{ + FLASH_ACR |= FLASH_ACR_ICE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the Instruction Cache + +*/ + +void flash_icache_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_ICE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the FLASH Prefetch Buffer + +This buffer is used for instruction fetches and is enabled by default after +reset. + +Note carefully the clock restrictions under which the prefetch buffer may be +enabled or disabled. Changes are normally made while the clock is running in +the power-on low frequency mode before being set to a higher speed mode. +See the reference manual for details. +*/ + +void flash_prefetch_enable(void) +{ + FLASH_ACR |= FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the FLASH Prefetch Buffer + +Note carefully the clock restrictions under which the prefetch buffer may be +set to disabled. See the reference manual for details. +*/ + +void flash_prefetch_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset the Data Cache + +The data cache must be disabled for this to have effect. +*/ + +void flash_dcache_reset(void) +{ + FLASH_ACR |= FLASH_ACR_DCRST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset the Instruction Cache + +The instruction cache must be disabled for this to have effect. +*/ + +void flash_icache_reset(void) +{ + FLASH_ACR |= FLASH_ACR_ICRST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Sequence Error Flag + +This flag is set when incorrect programming configuration has been made. +*/ + +void flash_clear_pgserr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGSERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Alignment Error Flag + +*/ + +void flash_clear_pgaerr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGAERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Write Protect Error Flag + +*/ + +void flash_clear_wrperr_flag(void) +{ + FLASH_SR |= FLASH_SR_WRPERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear All Status Flags + +Program error, end of operation, write protect error, busy. +*/ + +void flash_clear_status_flags(void) +{ + flash_clear_pgserr_flag(); + flash_clear_pgaerr_flag(); + flash_clear_wrperr_flag(); + flash_clear_pgperr_flag(); + flash_clear_eop_flag(); + flash_clear_bsy_flag(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Option Byte Access + +This enables write access to the option bytes. It is locked by default on +reset. +*/ + +void flash_unlock_option_bytes(void) +{ + /* Clear the unlock state. */ + FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK; + + /* Unlock option bytes. */ + FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1; + FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Option Byte Access + +This disables write access to the option bytes. It is locked by default on +reset. +*/ + +void flash_lock_option_bytes(void) +{ + FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a 64 bit Word to FLASH + +This performs all operations necessary to program a 64 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] uint32_t address +@param[in] uint64_t data. +*/ + +void flash_program_double_word(uint32_t address, uint64_t data) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X64); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_CR_PG; + + /* Program the double_word. */ + MMIO64(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a 32 bit Word to FLASH + +This performs all operations necessary to program a 32 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] uint32_t address +@param[in] uint32_t data. +*/ + +void flash_program_word(uint32_t address, uint32_t data) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X32); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_CR_PG; + + /* Program the word. */ + MMIO32(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Half Word to FLASH + +This performs all operations necessary to program a 16 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] uint32_t address +@param[in] uint16_t data. +*/ + +void flash_program_half_word(uint32_t address, uint16_t data) +{ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X16); + + FLASH_CR |= FLASH_CR_PG; + + MMIO16(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program an 8 bit Byte to FLASH + +This performs all operations necessary to program an 8 bit byte to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] uint32_t address +@param[in] uint8_t data. +*/ + +void flash_program_byte(uint32_t address, uint8_t data) +{ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X8); + + FLASH_CR |= FLASH_CR_PG; + + MMIO8(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Data Block to FLASH + +This programs an arbitrary length data block to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] uint32_t address. Starting address in Flash. +@param[in] uint8_t *data. Pointer to start of data block. +@param[in] uint32_t len. Length of data block. +*/ + +void flash_program(uint32_t address, uint8_t *data, uint32_t len) +{ + /* TODO: Use dword and word size program operations where possible for + * turbo speed. + */ + uint32_t i; + for (i = 0; i < len; i++) { + flash_program_byte(address+i, data[i]); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase a Sector of FLASH + +This performs all operations necessary to erase a sector in FLASH memory. +The page should be checked to ensure that it was properly erased. A sector must +first be fully erased before attempting to program it. + +See the reference manual or the FLASH programming manual for details. + +@param[in] uint32_t sector (0 - 11). +@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit) +*/ + +void flash_erase_sector(uint8_t sector, uint32_t program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR &= ~(0xF << 3); + FLASH_CR |= (sector << 3) & 0x78; + FLASH_CR |= FLASH_CR_SER; + FLASH_CR |= FLASH_CR_STRT; + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_SER; + FLASH_CR &= ~(0xF << 3); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase All FLASH + +This performs all operations necessary to erase all sectors in the FLASH +memory. + +@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit) +*/ + +void flash_erase_all_sectors(uint32_t program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */ + FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */ + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program the Option Bytes + +This performs all operations necessary to program the option bytes. +The option bytes do not need to be erased first. + +@param[in] uint32_t data to be programmed. +*/ + +void flash_program_option_bytes(uint32_t data) +{ + flash_wait_for_last_operation(); + + if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) { + flash_unlock_option_bytes(); + } + + FLASH_OPTCR = data & ~0x3; + FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */ + flash_wait_for_last_operation(); +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/gpio_common_all.c b/libopencm3/lib/stm32/common/gpio_common_all.c new file mode 100644 index 0000000..3821928 --- /dev/null +++ b/libopencm3/lib/stm32/common/gpio_common_all.c @@ -0,0 +1,151 @@ +/** @addtogroup gpio_file + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#define WEAK __attribute__((weak)) + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Set a Group of Pins Atomic + +Set one or more pins of the given GPIO port to 1 in an atomic operation. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be changed, use logical OR '|' to separate + them. +*/ +void gpio_set(uint32_t gpioport, uint16_t gpios) +{ + GPIO_BSRR(gpioport) = gpios; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear a Group of Pins Atomic + +Clear one or more pins of the given GPIO port to 0 in an atomic operation. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be changed, use logical OR '|' to separate + them. +*/ +void gpio_clear(uint32_t gpioport, uint16_t gpios) +{ + GPIO_BSRR(gpioport) = (gpios << 16); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read a Group of Pins. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be read, use logical OR '|' to separate + them. +@return Unsigned int16 value of the pin values. The bit position of the pin + value returned corresponds to the pin number. +*/ +uint16_t gpio_get(uint32_t gpioport, uint16_t gpios) +{ + return gpio_port_read(gpioport) & gpios; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Toggle a Group of Pins + +Toggle one or more pins of the given GPIO port. This is not an atomic operation. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be changed, use logical OR '|' to separate + them. +*/ +void gpio_toggle(uint32_t gpioport, uint16_t gpios) +{ + GPIO_ODR(gpioport) ^= gpios; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read from a Port + +Read the current value of the given GPIO port. Only the lower 16 bits contain +valid pin data. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@return Unsigned int16. The value held in the specified GPIO port. +*/ +uint16_t gpio_port_read(uint32_t gpioport) +{ + return (uint16_t)GPIO_IDR(gpioport); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Write to a Port + +Write a value to the given GPIO port. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] data Unsigned int16. The value to be written to the GPIO port. +*/ +void gpio_port_write(uint32_t gpioport, uint16_t data) +{ + GPIO_ODR(gpioport) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Configuration of a Group of Pins + +The configuration of one or more pins of the given GPIO port is locked. There +is no mechanism to unlock these via software. Unlocking occurs at the next +reset. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be locked, use logical OR '|' to separate + them. +*/ +void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios) +{ + uint32_t reg32; + + /* Special "Lock Key Writing Sequence", see datasheet. */ + GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */ + GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */ + GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */ + reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */ + reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */ + + /* Tell the compiler the variable is actually used. It will get + * optimized out anyways. + */ + reg32 = reg32; + + /* If (reg32 & GPIO_LCKK) is true, the lock is now active. */ +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/gpio_common_f0234.c b/libopencm3/lib/stm32/common/gpio_common_f0234.c new file mode 100644 index 0000000..9d79074 --- /dev/null +++ b/libopencm3/lib/stm32/common/gpio_common_f0234.c @@ -0,0 +1,206 @@ +/** @addtogroup gpio_file + +@author @htmlonly © @endhtmlonly 2009 +Uwe Hermann +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO +functionality with a number of alternate functions and must be configured to +the alternate function mode if these are to be accessed. A feature is available +to remap alternative functions to a limited set of alternative pins in the +event of a clash of requirements. + +The data registers associated with each port for input and output are 32 bit +with the upper 16 bits unused. The output buffer must be written as a 32 bit +word, but individual bits may be set or reset separately in atomic operations +to avoid race conditions during interrupts. Bits may also be individually +locked to prevent accidental configuration changes. Once locked the +configuration cannot be changed until after the next reset. + +Each port bit can be configured as analog or digital input, the latter can be +floating or pulled up or down. As outputs they can be configured as either +push-pull or open drain, digital I/O or alternate function, and with maximum +output speeds of 2MHz, 10MHz, or 50MHz. + +On reset all ports are configured as digital floating input. + +@section gpio_api_ex Basic GPIO Handling API. + +Example 1: Push-pull digital output actions with pullup on ports C2 and C9 + +@code + gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, + GPIO_PUPD_PULLUP, GPIO2 | GPIO9); + gpio_output_options(GPIOC, GPIO_OTYPE_PP, + GPIO_OSPEED_25MHZ, GPIO2 | GPIO9); + gpio_set(GPIOC, GPIO2 | GPIO9); + gpio_clear(GPIOC, GPIO2); + gpio_toggle(GPIOC, GPIO2 | GPIO9); + gpio_port_write(GPIOC, 0x204); +@endcode + +Example 2: Digital input on port C12 with pullup + +@code + gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, + GPIO_PUPD_PULLUP, GPIO12); + reg16 = gpio_port_read(GPIOC); +@endcode + +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set GPIO Pin Mode + +Sets the Pin Direction and Analog/Digital Mode, and Output Pin Pullup, +for a set of GPIO pins on a given GPIO port. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] mode Unsigned int8. Pin mode @ref gpio_mode +@param[in] pull_up_down Unsigned int8. Pin pullup/pulldown configuration @ref +gpio_pup +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be set, use bitwise OR '|' to separate + them. +*/ +void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down, + uint16_t gpios) +{ + uint16_t i; + uint32_t moder, pupd; + + /* + * We want to set the config only for the pins mentioned in gpios, + * but keeping the others, so read out the actual config first. + */ + moder = GPIO_MODER(gpioport); + pupd = GPIO_PUPDR(gpioport); + + for (i = 0; i < 16; i++) { + if (!((1 << i) & gpios)) { + continue; + } + + moder &= ~GPIO_MODE_MASK(i); + moder |= GPIO_MODE(i, mode); + pupd &= ~GPIO_PUPD_MASK(i); + pupd |= GPIO_PUPD(i, pull_up_down); + } + + /* Set mode and pull up/down control registers. */ + GPIO_MODER(gpioport) = moder; + GPIO_PUPDR(gpioport) = pupd; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set GPIO Output Options + +When the pin is set to output mode, this sets the configuration (analog/digital +and open drain/push pull) and speed, for a set of GPIO pins on a given GPIO +port. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] otype Unsigned int8. Pin output type @ref gpio_output_type +@param[in] speed Unsigned int8. Pin speed @ref gpio_speed +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be set, use bitwise OR '|' to separate + them. +*/ +void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed, + uint16_t gpios) +{ + uint16_t i; + uint32_t ospeedr; + + if (otype == 0x1) { + GPIO_OTYPER(gpioport) |= gpios; + } else { + GPIO_OTYPER(gpioport) &= ~gpios; + } + + ospeedr = GPIO_OSPEEDR(gpioport); + + for (i = 0; i < 16; i++) { + if (!((1 << i) & gpios)) { + continue; + } + ospeedr &= ~GPIO_OSPEED_MASK(i); + ospeedr |= GPIO_OSPEED(i, speed); + } + + GPIO_OSPEEDR(gpioport) = ospeedr; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set GPIO Alternate Function Selection + +Set the alternate function mapping number for each pin. Most pins have +alternate functions associated with them. When set to AF mode, a pin may be +used for one of its allocated alternate functions selected by the number given +here. To determine the number to be used for the desired function refer to the +individual datasheet for the particular device. A table is given under the Pin +Selection chapter. + +Note that a number of pins may be set but only with a single AF number. In +practice this would rarely be useful as each pin is likely to require a +different number. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] alt_func_num Unsigned int8. Pin alternate function number @ref +gpio_af_num +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be set, use bitwise OR '|' to separate + them. +*/ +void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios) +{ + uint16_t i; + uint32_t afrl, afrh; + + afrl = GPIO_AFRL(gpioport); + afrh = GPIO_AFRH(gpioport); + + for (i = 0; i < 8; i++) { + if (!((1 << i) & gpios)) { + continue; + } + afrl &= ~GPIO_AFR_MASK(i); + afrl |= GPIO_AFR(i, alt_func_num); + } + + for (i = 8; i < 16; i++) { + if (!((1 << i) & gpios)) { + continue; + } + afrh &= ~GPIO_AFR_MASK(i - 8); + afrh |= GPIO_AFR(i - 8, alt_func_num); + } + + GPIO_AFRL(gpioport) = afrl; + GPIO_AFRH(gpioport) = afrh; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/hash_common_f24.c b/libopencm3/lib/stm32/common/hash_common_f24.c new file mode 100644 index 0000000..24d489c --- /dev/null +++ b/libopencm3/lib/stm32/common/hash_common_f24.c @@ -0,0 +1,163 @@ +/** @addtogroup hash_file + * + * @author @htmlonly © @endhtmlonly 2013 + * Mikhail Avkhimenia + * + * This library supports the HASH processor in the STM32F2 and STM32F4 + * series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + * */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Mikhail Avkhimenia + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Set Mode + +Sets up the specified mode - either HASH or HMAC. + +@param[in] mode unsigned int8. Hash processor mode: @ref hash_mode +*/ + +void hash_set_mode(uint8_t mode) +{ + HASH_CR &= ~HASH_CR_MODE; + HASH_CR |= mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Set Algorithm + +Sets up the specified algorithm - either MD5 or SHA1. + +@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm +*/ + +void hash_set_algorithm(uint8_t algorithm) +{ + HASH_CR &= ~HASH_CR_ALGO; + HASH_CR |= algorithm; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Set Data Type + +Sets up the specified data type: 32Bit, 16Bit, 8Bit, Bitstring. + +@param[in] datatype unsigned int8. Hash data type: @ref hash_data_type +*/ + +void hash_set_data_type(uint8_t datatype) +{ + HASH_CR &= ~HASH_CR_DATATYPE; + HASH_CR |= datatype; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Set Key Length + +Sets up the specified key length: Long, Short. + +@param[in] keylength unsigned int8. Hash data type: @ref hash_key_length +*/ + +void hash_set_key_length(uint8_t keylength) +{ + HASH_CR &= ~HASH_CR_LKEY; + HASH_CR |= keylength; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Set Last Word Valid Bits + +Specifies the number of valid bits in the last word. + +@param[in] validbits unsigned int8. Number of valid bits. +*/ + +void hash_set_last_word_valid_bits(uint8_t validbits) +{ + HASH_STR &= ~(HASH_STR_NBW); + HASH_STR |= validbits; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Init + +Initializes the HASH processor. + +*/ + +void hash_init() +{ + HASH_CR |= HASH_CR_INIT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Add data + +Puts data into the HASH processor's queue. + +@param[in] data unsigned int32. Hash input data. +*/ + +void hash_add_data(uint32_t data) +{ + HASH_DIN = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Digest + +Starts the processing of the last data block. + +*/ + +void hash_digest() +{ + HASH_STR |= HASH_STR_DCAL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief HASH Get Hash Result + +Makes a copy of the resulting hash. + +@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm. +@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm +*/ + +void hash_get_result(uint32_t *data) +{ + data[0] = HASH_HR[0]; + data[1] = HASH_HR[1]; + data[2] = HASH_HR[2]; + data[3] = HASH_HR[3]; + + if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) { + data[4] = HASH_HR[4]; + } +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/i2c_common_all.c b/libopencm3/lib/stm32/common/i2c_common_all.c new file mode 100644 index 0000000..886f594 --- /dev/null +++ b/libopencm3/lib/stm32/common/i2c_common_all.c @@ -0,0 +1,419 @@ +/** @addtogroup i2c_file + +@author @htmlonly © @endhtmlonly 2010 +Thomas Otto +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +Devices can have up to three I2C peripherals. The peripherals support SMBus and +PMBus variants. + +A peripheral begins after reset in Slave mode. To become a Master a start +condition must be generated. The peripheral will remain in Master mode unless +a multimaster contention is lost or a stop condition is generated. + +@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status +register access, Error conditions + +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Reset. + +The I2C peripheral and all its associated configuration registers are placed in +the reset condition. The reset is effected via the RCC peripheral reset system. + +@param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base. +*/ + +void i2c_reset(uint32_t i2c) +{ + switch (i2c) { + case I2C1: + rcc_periph_reset_pulse(RST_I2C1); + break; +#if defined(I2C2_BASE) + case I2C2: + rcc_periph_reset_pulse(RST_I2C2); + break; +#endif +#if defined(I2C3_BASE) + case I2C3: + rcc_periph_reset_pulse(RST_I2C3); + break; +#endif + default: + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Peripheral Enable. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_peripheral_enable(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_PE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Peripheral Disable. + +This must not be reset while in Master mode until a communication has finished. +In Slave mode, the peripheral is disabled only after communication has ended. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_peripheral_disable(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_PE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Start Condition. + +If in Master mode this will cause a restart condition to occur at the end of the +current transmission. If in Slave mode, this will initiate a start condition +when the current bus activity is completed. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_send_start(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_START; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Stop Condition. + +After the current byte transfer this will initiate a stop condition if in Master +mode, or simply release the bus if in Slave mode. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_send_stop(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_STOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Clear Stop Flag. + +Clear the "Send Stop" flag in the I2C config register + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_clear_stop(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_STOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set the 7 bit Slave Address for the Peripheral. + +This sets an address for Slave mode operation, in 7 bit form. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] slave Unsigned int8. Slave address 0...127. +*/ + +void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave) +{ + I2C_OAR1(i2c) = (uint16_t)(slave << 1); + I2C_OAR1(i2c) &= ~I2C_OAR1_ADDMODE; + I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set the 10 bit Slave Address for the Peripheral. + +This sets an address for Slave mode operation, in 10 bit form. + +@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] slave Unsigned int16. Slave address 0...1023. +*/ + +void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave) +{ + I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave); +} + + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set Peripheral Clock Frequency. + +Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note +that this is not the I2C bus clock. This is set in conjunction with +the Clock Control register to generate the Master bus clock, see @ref +i2c_set_ccr + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] freq Unsigned int8. Clock Frequency Setting @ref i2c_clock. +*/ + +void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq) +{ + uint16_t reg16; + reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */ + reg16 |= freq; + I2C_CR2(i2c) = reg16; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Data. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] data Unsigned int8. Byte to send. +*/ + +void i2c_send_data(uint32_t i2c, uint8_t data) +{ + I2C_DR(i2c) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set Fast Mode. + +Set the clock frequency to the high clock rate mode (up to 400kHz). The actual +clock frequency must be set with @ref i2c_set_clock_frequency + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_set_fast_mode(uint32_t i2c) +{ + I2C_CCR(i2c) |= I2C_CCR_FS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set Standard Mode. + +Set the clock frequency to the standard clock rate mode (up to 100kHz). The +actual clock frequency must be set with @ref i2c_set_clock_frequency + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ + +void i2c_set_standard_mode(uint32_t i2c) +{ + I2C_CCR(i2c) &= ~I2C_CCR_FS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set Bus Clock Frequency. + +Set the bus clock frequency. This is a 12 bit number (0...4095) calculated +from the formulae given in the STM32F1 reference manual in the description +of the CCR field. It is a divisor of the peripheral clock frequency +@ref i2c_set_clock_frequency modified by the fast mode setting +@ref i2c_set_fast_mode + +@todo provide additional API assitance to set the clock, eg macros + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095. +*/ + +void i2c_set_ccr(uint32_t i2c, uint16_t freq) +{ + uint16_t reg16; + reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */ + reg16 |= freq; + I2C_CCR(i2c) = reg16; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set the Rise Time. + +Set the maximum rise time on the bus according to the I2C specification, as 1 +more than the specified rise time in peripheral clock cycles. This is a 6 bit +number. + +@todo provide additional APIP assistance. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] trise Unsigned int16. Rise Time Setting 0...63. +*/ + +void i2c_set_trise(uint32_t i2c, uint16_t trise) +{ + I2C_TRISE(i2c) = trise; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send the 7-bit Slave Address. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] slave Unsigned int16. Slave address 0...1023. +@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or +send @ref i2c_rw. +*/ + +void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite) +{ + I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite); +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Get Data. + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +uint8_t i2c_get_data(uint32_t i2c) +{ + return I2C_DR(i2c) & 0xff; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable Interrupt + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] interrupt Unsigned int32. Interrupt to enable. +*/ +void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt) +{ + I2C_CR2(i2c) |= interrupt; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable Interrupt + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] interrupt Unsigned int32. Interrupt to disable. +*/ +void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt) +{ + I2C_CR2(i2c) &= ~interrupt; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable ACK + +Enables acking of own 7/10 bit address +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_enable_ack(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_ACK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable ACK + +Disables acking of own 7/10 bit address +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_disable_ack(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_ACK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C NACK Next Byte + +Causes the I2C controller to NACK the reception of the next byte +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_nack_next(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_POS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C NACK Next Byte + +Causes the I2C controller to NACK the reception of the current byte + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_nack_current(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_POS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set clock duty cycle + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle. +*/ +void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle) +{ + if (dutycycle == I2C_CCR_DUTY_DIV2) { + I2C_CCR(i2c) &= ~I2C_CCR_DUTY; + } else { + I2C_CCR(i2c) |= I2C_CCR_DUTY; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable DMA + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_enable_dma(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable DMA + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_disable_dma(uint32_t i2c) +{ + I2C_CR2(i2c) &= ~I2C_CR2_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set DMA last transfer + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_set_dma_last_transfer(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_LAST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Clear DMA last transfer + +@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. +*/ +void i2c_clear_dma_last_transfer(uint32_t i2c) +{ + I2C_CR2(i2c) &= ~I2C_CR2_LAST; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/iwdg_common_all.c b/libopencm3/lib/stm32/common/iwdg_common_all.c new file mode 100644 index 0000000..d9aca5a --- /dev/null +++ b/libopencm3/lib/stm32/common/iwdg_common_all.c @@ -0,0 +1,149 @@ +/** @addtogroup iwdg_file + +@author @htmlonly © @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net + +This library supports the Independent Watchdog Timer System in the STM32F1xx +series of ARM Cortex Microcontrollers by ST Microelectronics. + +The watchdog timer uses the LSI (low speed internal) clock which is low power +and continues to operate during stop and standby modes. Its frequency is +nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low +as 17kHz up to 60kHz (refer to datasheet electrical characteristics). + +Note that the User Configuration option byte provides a means of automatically +enabling the IWDG timer at power on (with counter value 0xFFF). If the +relevant bit is not set, the IWDG timer must be enabled by software. + +@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32 + +*/ +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +#define LSI_FREQUENCY 32000 +#define COUNT_LENGTH 12 +#define COUNT_MASK ((1 << COUNT_LENGTH)-1) + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG Enable Watchdog Timer + +The watchdog timer is started. The timeout period defaults to 512 milliseconds +unless it has been previously defined. + +*/ + +void iwdg_start(void) +{ + IWDG_KR = IWDG_KR_START; +} + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG Set Period in Milliseconds + +The countdown period is converted into count and prescale values. The maximum +period is 32.76 seconds; values above this are truncated. Periods less than 1ms +are not supported by this library. + +A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds) +can occasionally occur if the prescale or preload registers are currently busy +loading a previous value. + +@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog +reset until a system reset is issued. +*/ + +void iwdg_set_period_ms(uint32_t period) +{ + uint32_t count, prescale, reload, exponent; + + /* Set the count to represent ticks of the 32kHz LSI clock */ + count = (period << 5); + + /* Strip off the first 12 bits to get the prescale value required */ + prescale = (count >> 12); + if (prescale > 256) { + exponent = IWDG_PR_DIV256; reload = COUNT_MASK; + } else if (prescale > 128) { + exponent = IWDG_PR_DIV256; reload = (count >> 8); + } else if (prescale > 64) { + exponent = IWDG_PR_DIV128; reload = (count >> 7); + } else if (prescale > 32) { + exponent = IWDG_PR_DIV64; reload = (count >> 6); + } else if (prescale > 16) { + exponent = IWDG_PR_DIV32; reload = (count >> 5); + } else if (prescale > 8) { + exponent = IWDG_PR_DIV16; reload = (count >> 4); + } else if (prescale > 4) { + exponent = IWDG_PR_DIV8; reload = (count >> 3); + } else { + exponent = IWDG_PR_DIV4; reload = (count >> 2); + } + + /* Avoid the undefined situation of a zero count */ + if (count == 0) { + count = 1; + } + + while (iwdg_prescaler_busy()); + IWDG_KR = IWDG_KR_UNLOCK; + IWDG_PR = exponent; + while (iwdg_reload_busy()); + IWDG_KR = IWDG_KR_UNLOCK; + IWDG_RLR = (reload & COUNT_MASK); +} + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG Get Reload Register Status + +@returns boolean: TRUE if the reload register is busy and unavailable for +loading a new count value. +*/ + +bool iwdg_reload_busy(void) +{ + return IWDG_SR & IWDG_SR_RVU; +} + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG Get Prescaler Register Status + +@returns boolean: TRUE if the prescaler register is busy and unavailable for +loading a new period value. +*/ + +bool iwdg_prescaler_busy(void) +{ + return IWDG_SR & IWDG_SR_PVU; +} + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG reset Watchdog Timer + +The watchdog timer is reset. The counter restarts from the value in the reload +register. +*/ + +void iwdg_reset(void) +{ + IWDG_KR = IWDG_KR_RESET; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/pwr_common_all.c b/libopencm3/lib/stm32/common/pwr_common_all.c new file mode 100644 index 0000000..53e6b42 --- /dev/null +++ b/libopencm3/lib/stm32/common/pwr_common_all.c @@ -0,0 +1,205 @@ +/** @addtogroup pwr_file PWR + +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Backup Domain Write Protection. + +This allows backup domain registers to be changed. These registers are write +protected after a reset. +*/ + +void pwr_disable_backup_domain_write_protect(void) +{ + PWR_CR |= PWR_CR_DBP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Re-enable Backup Domain Write Protection. + +This protects backup domain registers from inadvertent change. +*/ + +void pwr_enable_backup_domain_write_protect(void) +{ + PWR_CR &= ~PWR_CR_DBP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Power Voltage Detector. + +This provides voltage level threshold detection. The result of detection is +provided in the power voltage detector output flag (see @ref pwr_voltage_high) +or by setting the EXTI16 interrupt (see datasheet for configuration details). + +@param[in] pvd_level uint32_t. Taken from @ref pwr_pls. +*/ + +void pwr_enable_power_voltage_detect(uint32_t pvd_level) +{ + PWR_CR &= ~PWR_CR_PLS_MASK; + PWR_CR |= (PWR_CR_PVDE | pvd_level); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Power Voltage Detector. + +*/ + +void pwr_disable_power_voltage_detect(void) +{ + PWR_CR &= ~PWR_CR_PVDE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Standby Flag. + +This is set when the processor returns from a standby mode. +*/ + +void pwr_clear_standby_flag(void) +{ + PWR_CR |= PWR_CR_CSBF; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Wakeup Flag. + +This is set when the processor receives a wakeup signal. +*/ + +void pwr_clear_wakeup_flag(void) +{ + PWR_CR |= PWR_CR_CWUF; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Standby Mode in Deep Sleep. + +*/ + +void pwr_set_standby_mode(void) +{ + PWR_CR |= PWR_CR_PDDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Stop Mode in Deep Sleep. + +*/ + +void pwr_set_stop_mode(void) +{ + PWR_CR &= ~PWR_CR_PDDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Voltage Regulator On in Stop Mode. + +*/ + +void pwr_voltage_regulator_on_in_stop(void) +{ + PWR_CR &= ~PWR_CR_LPDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Voltage Regulator Low Power in Stop Mode. + +*/ + +void pwr_voltage_regulator_low_power_in_stop(void) +{ + PWR_CR |= PWR_CR_LPDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Wakeup Pin. + +The wakeup pin is used for waking the processor from standby mode. +*/ + +void pwr_enable_wakeup_pin(void) +{ + PWR_CSR |= PWR_CSR_EWUP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Release Wakeup Pin. + +The wakeup pin is used for general purpose I/O. +*/ + +void pwr_disable_wakeup_pin(void) +{ + PWR_CSR &= ~PWR_CSR_EWUP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get Voltage Detector Output. + +The voltage detector threshold must be set when the power voltage detector is +enabled, see @ref pwr_enable_power_voltage_detect. + +@returns boolean: TRUE if the power voltage is above the preset voltage +threshold. +*/ + +bool pwr_voltage_high(void) +{ + return PWR_CSR & PWR_CSR_PVDO; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get Standby Flag. + +The standby flag is set when the processor returns from a standby state. It is +cleared by software (see @ref pwr_clear_standby_flag). + +@returns boolean: TRUE if the processor was in standby state. +*/ + +bool pwr_get_standby_flag(void) +{ + return PWR_CSR & PWR_CSR_SBF; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get Wakeup Flag. + +The wakeup flag is set when a wakeup event has been received. It is +cleared by software (see @ref pwr_clear_wakeup_flag). + +@returns boolean: TRUE if a wakeup event was received. +*/ + +bool pwr_get_wakeup_flag(void) +{ + return PWR_CSR & PWR_CSR_WUF; +} +/**@}*/ diff --git a/libopencm3/lib/stm32/common/rcc_common_all.c b/libopencm3/lib/stm32/common/rcc_common_all.c new file mode 100644 index 0000000..41cb814 --- /dev/null +++ b/libopencm3/lib/stm32/common/rcc_common_all.c @@ -0,0 +1,188 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * .. file is merged from many other copyrighted files of stm32 family + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable Peripheral Clocks. + * + * Enable the clock on particular peripherals. There are three registers + * involved, each one controlling the enabling of clocks associated with the + * AHB, APB1 and APB2 respectively. Several peripherals could be enabled + * simultaneously only if they are controlled by the same register. + * + * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register + * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR) + * + * @param[in] en Unsigned int32. Logical OR of all enables to be set + * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en + * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en + * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en + */ + +void rcc_peripheral_enable_clock(volatile uint32_t *reg, uint32_t en) +{ + *reg |= en; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable Peripheral Clocks. + * + * Enable the clock on particular peripherals. There are three registers + * involved, each one controlling the enabling of clocks associated with + * the AHB, APB1 and APB2 respectively. Several peripherals could be disabled + * simultaneously only if they are controlled by the same register. + * + * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register + * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR) + * @param[in] en Unsigned int32. Logical OR of all enables to be used for + * disabling. + * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en + * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en + * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en + */ +void rcc_peripheral_disable_clock(volatile uint32_t *reg, uint32_t en) +{ + *reg &= ~en; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Reset Peripherals. + * + * Reset particular peripherals. There are three registers involved, each one + * controlling reset of peripherals associated with the AHB, APB1 and APB2 + * respectively. Several peripherals could be reset simultaneously only if + * they are controlled by the same register. + * + * @param[in] *reg Unsigned int32. Pointer to a Reset Register + * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR) + * @param[in] reset Unsigned int32. Logical OR of all resets. + * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst + * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst + * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst + */ +void rcc_peripheral_reset(volatile uint32_t *reg, uint32_t reset) +{ + *reg |= reset; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Remove Reset on Peripherals. + * + * Remove the reset on particular peripherals. There are three registers + * involved, each one controlling reset of peripherals associated with the AHB, + * APB1 and APB2 respectively. Several peripherals could have the reset removed + * simultaneously only if they are controlled by the same register. + * + * @param[in] *reg Unsigned int32. Pointer to a Reset Register + * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR) + * @param[in] clear_reset Unsigned int32. Logical OR of all resets to be + * removed: + * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst + * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst + * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst + */ +void rcc_peripheral_clear_reset(volatile uint32_t *reg, uint32_t clear_reset) +{ + *reg &= ~clear_reset; +} + +#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5)) +#define _RCC_BIT(i) (1 << ((i) & 0x1f)) + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Peripheral Clock in running mode. + * + * Enable the clock on particular peripheral. + * + * @param[in] clken rcc_periph_clken Peripheral RCC + * + * For available constants, see #rcc_periph_clken (RCC_UART1 for example) + */ + +void rcc_periph_clock_enable(enum rcc_periph_clken clken) +{ + _RCC_REG(clken) |= _RCC_BIT(clken); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Peripheral Clock in running mode. + * Disable the clock on particular peripheral. + * + * @param[in] clken rcc_periph_clken Peripheral RCC + * + * For available constants, see #rcc_periph_clken (RCC_UART1 for example) + */ + +void rcc_periph_clock_disable(enum rcc_periph_clken clken) +{ + _RCC_REG(clken) &= ~_RCC_BIT(clken); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset Peripheral, pulsed + * + * Reset particular peripheral, and restore to working state. + * + * @param[in] rst rcc_periph_rst Peripheral reset + * + * For available constants, see #rcc_periph_rst (RST_UART1 for example) + */ + +void rcc_periph_reset_pulse(enum rcc_periph_rst rst) +{ + _RCC_REG(rst) |= _RCC_BIT(rst); + _RCC_REG(rst) &= ~_RCC_BIT(rst); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset Peripheral, hold + * + * Reset particular peripheral, and hold in reset state. + * + * @param[in] rst rcc_periph_rst Peripheral reset + * + * For available constants, see #rcc_periph_rst (RST_UART1 for example) + */ + +void rcc_periph_reset_hold(enum rcc_periph_rst rst) +{ + _RCC_REG(rst) |= _RCC_BIT(rst); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset Peripheral, release + * + * Restore peripheral from reset state to working state. + * + * @param[in] rst rcc_periph_rst Peripheral reset + * + * For available constants, see #rcc_periph_rst (RST_UART1 for example) + */ + +void rcc_periph_reset_release(enum rcc_periph_rst rst) +{ + _RCC_REG(rst) &= ~_RCC_BIT(rst); +} +/**@}*/ + +#undef _RCC_REG +#undef _RCC_BIT diff --git a/libopencm3/lib/stm32/common/rtc_common_l1f024.c b/libopencm3/lib/stm32/common/rtc_common_l1f024.c new file mode 100644 index 0000000..7579dfd --- /dev/null +++ b/libopencm3/lib/stm32/common/rtc_common_l1f024.c @@ -0,0 +1,123 @@ +/** @addtogroup rtc_file + +@author @htmlonly © @endhtmlonly 2012 Karl Palsson + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set RTC prescalars. + +This sets the RTC synchronous and asynchronous prescalars. +*/ + +void rtc_set_prescaler(uint32_t sync, uint32_t async) +{ + /* + * Even if only one of the two fields needs to be changed, + * 2 separate write accesses must be performed to the RTC_PRER register. + */ + RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK); + RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Wait for RTC registers to be synchronised with the APB1 bus + + Time and Date are accessed through shadow registers which must be synchronized +*/ + +void rtc_wait_for_synchro(void) +{ + /* Unlock RTC registers */ + RTC_WPR = 0xca; + RTC_WPR = 0x53; + + RTC_ISR &= ~(RTC_ISR_RSF); + + while (!(RTC_ISR & RTC_ISR_RSF)); + + /* disable write protection again */ + RTC_WPR = 0xff; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock write access to the RTC registers + +*/ +void rtc_unlock(void) +{ + RTC_WPR = 0xca; + RTC_WPR = 0x53; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock write access to the RTC registers + +*/ +void rtc_lock(void) +{ + RTC_WPR = 0xff; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Sets the wakeup time auto-reload value + +*/ +void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel) +{ + /* FTFM: + * The following sequence is required to configure or change the wakeup + * timer auto-reload value (WUT[15:0] in RTC_WUTR): + * 1. Clear WUTE in RTC_CR to disable the wakeup timer. + */ + RTC_CR &= ~RTC_CR_WUTE; + /* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to + * wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed. + * It takes around 2 RTCCLK clock cycles (due to clock + * synchronization). + */ + while (!((RTC_ISR) & (RTC_ISR_WUTWF))); + /* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup + * clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR + * to enable the timer again. The wakeup timer restarts + * down-counting. + */ + RTC_WUTR = wkup_time; + RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT); + RTC_CR |= RTC_CR_WUTE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clears the wakeup flag + +@details This function should be called first in the rtc_wkup_isr() +*/ +void rtc_clear_wakeup_flag(void) +{ + RTC_ISR &= ~RTC_ISR_WUTF; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/spi_common_all.c b/libopencm3/lib/stm32/common/spi_common_all.c new file mode 100644 index 0000000..6572233 --- /dev/null +++ b/libopencm3/lib/stm32/common/spi_common_all.c @@ -0,0 +1,710 @@ +/** @addtogroup spi_file + +@author @htmlonly © @endhtmlonly 2009 +Uwe Hermann +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +Devices can have up to three SPI peripherals. The common 4-wire full-duplex +mode of operation is supported, along with 3-wire variants using unidirectional +communication modes or half-duplex bidirectional communication. A variety of +options allows many of the SPI variants to be supported. Multimaster operation +is also supported. A CRC can be generated and checked in hardware. + +@note Some JTAG pins need to be remapped if SPI is to be used. + +@note The I2S protocol shares the SPI hardware so the two protocols cannot be +used at the same time on the same peripheral. + +Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words, +LSB first. +@code + spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, + SPI_CR1_LSBFIRST); + spi_write(SPI1, 0x55); // 8-bit write + spi_write(SPI1, 0xaa88); // 16-bit write + reg8 = spi_read(SPI1); // 8-bit read + reg16 = spi_read(SPI1); // 16-bit read +@endcode + +@todo need additional functions to aid ISRs in retrieving status + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/* + * SPI and I2S code. + * + * Examples: + * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, + * SPI_CR1_LSBFIRST); + * spi_write(SPI1, 0x55); // 8-bit write + * spi_write(SPI1, 0xaa88); // 16-bit write + * reg8 = spi_read(SPI1); // 8-bit read + * reg16 = spi_read(SPI1); // 16-bit read + */ + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Reset. + +The SPI peripheral and all its associated configuration registers are placed in +the reset condition. The reset is effected via the RCC peripheral reset system. + +@param[in] spi_peripheral Unsigned int32. SPI peripheral identifier @ref +spi_reg_base. +*/ + +void spi_reset(uint32_t spi_peripheral) +{ switch (spi_peripheral) { +#if defined(SPI1_BASE) + case SPI1_BASE: + rcc_periph_reset_pulse(RST_SPI1); + break; +#endif +#if defined(SPI2_I2S_BASE) + case SPI2_I2S_BASE: + rcc_periph_reset_pulse(RST_SPI2); + break; +#endif +#if defined(SPI3_I2S_BASE) + case SPI3_I2S_BASE: + rcc_periph_reset_pulse(RST_SPI3); + break; +#endif +#if defined(SPI4_BASE) + case SPI4_BASE: + rcc_periph_reset_pulse(RST_SPI4); + break; +#endif +#if defined(SPI5_BASE) + case SPI5_BASE: + rcc_periph_reset_pulse(RST_SPI5); + break; +#endif +#if defined(SPI6_BASE) + case SPI6_BASE: + rcc_periph_reset_pulse(RST_SPI6); + break; +#endif + default: + break; + } +} + +/* TODO: Error handling? */ +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable. + +The SPI peripheral is enabled. + +@todo Error handling? + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */ +} + +/* TODO: Error handling? */ +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable. + +The SPI peripheral is disabled. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable(uint32_t spi) +{ + uint32_t reg32; + + reg32 = SPI_CR1(spi); + reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */ + SPI_CR1(spi) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Clean Disable. + +Disable the SPI peripheral according to the procedure in section 23.3.8 of the +reference manual. This prevents corruption of any ongoing transfers and +prevents the BSY flag from becoming unreliable. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@returns data Unsigned int16. 8 or 16 bit data from final read. +*/ + +uint16_t spi_clean_disable(uint32_t spi) +{ + /* Wait to receive last data */ + while (!(SPI_SR(spi) & SPI_SR_RXNE)); + + uint16_t data = SPI_DR(spi); + + /* Wait to transmit last data */ + while (!(SPI_SR(spi) & SPI_SR_TXE)); + + /* Wait until not busy */ + while (SPI_SR(spi) & SPI_SR_BSY); + + SPI_CR1(spi) &= ~SPI_CR1_SPE; + + return data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Data Write. + +Data is written to the SPI interface. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] data Unsigned int16. 8 or 16 bit data to be written. +*/ + +void spi_write(uint32_t spi, uint16_t data) +{ + /* Write data (8 or 16 bits, depending on DFF) into DR. */ + SPI_DR(spi) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Data Write with Blocking. + +Data is written to the SPI interface after the previous write transfer has +finished. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] data Unsigned int16. 8 or 16 bit data to be written. +*/ + +void spi_send(uint32_t spi, uint16_t data) +{ + /* Wait for transfer finished. */ + while (!(SPI_SR(spi) & SPI_SR_TXE)); + + /* Write data (8 or 16 bits, depending on DFF) into DR. */ + SPI_DR(spi) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Data Read. + +Data is read from the SPI interface after the incoming transfer has finished. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@returns data Unsigned int16. 8 or 16 bit data. +*/ + +uint16_t spi_read(uint32_t spi) +{ + /* Wait for transfer finished. */ + while (!(SPI_SR(spi) & SPI_SR_RXNE)); + + /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */ + return SPI_DR(spi); +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Data Write and Read Exchange. + +Data is written to the SPI interface, then a read is done after the incoming +transfer has finished. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] data Unsigned int16. 8 or 16 bit data to be written. +@returns data Unsigned int16. 8 or 16 bit data. +*/ + +uint16_t spi_xfer(uint32_t spi, uint16_t data) +{ + spi_write(spi, data); + + /* Wait for transfer finished. */ + while (!(SPI_SR(spi) & SPI_SR_RXNE)); + + /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */ + return SPI_DR(spi); +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Bidirectional Simplex Mode. + +The SPI peripheral is set for bidirectional transfers in two-wire simplex mode +(using a clock wire and a bidirectional data wire). + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_bidirectional_mode(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_BIDIMODE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Unidirectional Mode. + +The SPI peripheral is set for unidirectional transfers. This is used in full +duplex mode or when the SPI is placed in two-wire simplex mode that uses a +clock wire and a unidirectional data wire. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_unidirectional_mode(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Bidirectional Simplex Receive Only Mode. + +The SPI peripheral is set for bidirectional transfers in two-wire simplex mode +(using a clock wire and a bidirectional data wire), and is placed in a receive +state. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_bidirectional_receive_only_mode(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_BIDIMODE; + SPI_CR1(spi) &= ~SPI_CR1_BIDIOE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Bidirectional Simplex Receive Only Mode. + +The SPI peripheral is set for bidirectional transfers in two-wire simplex mode +(using a clock wire and a bidirectional data wire), and is placed in a transmit +state. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_bidirectional_transmit_only_mode(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_BIDIMODE; + SPI_CR1(spi) |= SPI_CR1_BIDIOE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable the CRC. + +The SPI peripheral is set to use a CRC field for transmit and receive. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_crc(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_CRCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable the CRC. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_crc(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_CRCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Next Transmit is a Data Word + +The next transmission to take place is a data word from the transmit buffer. +This must be called before transmission to distinguish between sending +of a data or CRC word. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_next_tx_from_buffer(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Next Transmit is a CRC Word + +The next transmission to take place is a crc word from the hardware crc unit. +This must be called before transmission to distinguish between sending +of a data or CRC word. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_next_tx_from_crc(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_CRCNEXT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Full Duplex (3-wire) Mode + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_full_duplex_mode(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_RXONLY; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional +Transfers + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_receive_only_mode(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_RXONLY; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable Slave Management by Hardware + +In slave mode the NSS hardware input is used as a select enable for the slave. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_software_slave_management(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_SSM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable Slave Management by Software + +In slave mode the NSS hardware input is replaced by an internal software +enable/disable of the slave (@ref spi_set_nss_high). + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_software_slave_management(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_SSM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Software NSS Signal High + +In slave mode, and only when software slave management is used, this replaces +the NSS signal with a slave select enable signal. + +@todo these should perhaps be combined with an SSM enable as it is meaningless +otherwise + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_nss_high(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_SSI; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Software NSS Signal Low + +In slave mode, and only when software slave management is used, this replaces +the NSS signal with a slave select disable signal. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_nss_low(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_SSI; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set to Send LSB First + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_send_lsb_first(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_LSBFIRST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set to Send MSB First + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_send_msb_first(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Baudrate Prescaler + +@todo Why is this specification different to the spi_init_master baudrate +values? + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre. +*/ + +void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate) +{ + uint32_t reg32; + + if (baudrate > 7) { + return; + } + + reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */ + reg32 |= (baudrate << 3); + SPI_CR1(spi) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set to Master Mode + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_master_mode(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_MSTR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set to Slave Mode + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_slave_mode(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_MSTR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Clock Polarity to High when Idle + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_clock_polarity_1(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_CPOL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Clock Polarity to Low when Idle + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_clock_polarity_0(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_CPOL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Clock Phase to Capture on Trailing Edge + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_clock_phase_1(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_CPHA; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the Clock Phase to Capture on Leading Edge + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_clock_phase_0(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_CPHA; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable the Transmit Buffer Empty Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_tx_buffer_empty_interrupt(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable the Transmit Buffer Empty Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_tx_buffer_empty_interrupt(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable the Receive Buffer Ready Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_RXNEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable the Receive Buffer Ready Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_RXNEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable the Error Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_error_interrupt(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_ERRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable the Error Interrupt + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_error_interrupt(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_ERRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the NSS Pin as an Output + +Normally used in master mode to allows the master to place all devices on the +SPI bus into slave mode. Multimaster mode is not possible. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_ss_output(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_SSOE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set the NSS Pin as an Input + +In master mode this allows the master to sense the presence of other masters. If +NSS is then pulled low the master is placed into slave mode. In slave mode NSS +becomes a slave enable. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_ss_output(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_SSOE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable Transmit Transfers via DMA + +This allows transmissions to proceed unattended using DMA to move data to the +transmit buffer as it becomes available. The DMA channels provided for each +SPI peripheral are given in the Technical Manual DMA section. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_tx_dma(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_TXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable Transmit Transfers via DMA + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_tx_dma(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Enable Receive Transfers via DMA + +This allows received data streams to proceed unattended using DMA to move data +from the receive buffer as data becomes available. The DMA channels provided +for each SPI peripheral are given in the Technical Manual DMA section. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_enable_rx_dma(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_RXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Disable Receive Transfers via DMA + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_disable_rx_dma(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/spi_common_f03.c b/libopencm3/lib/stm32/common/spi_common_f03.c new file mode 100644 index 0000000..5713653 --- /dev/null +++ b/libopencm3/lib/stm32/common/spi_common_f03.c @@ -0,0 +1,177 @@ +/** @addtogroup spi_file + +@author @htmlonly © @endhtmlonly 2009 +Uwe Hermann +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +Devices can have up to three SPI peripherals. The common 4-wire full-duplex +mode of operation is supported, along with 3-wire variants using unidirectional +communication modes or half-duplex bidirectional communication. A variety of +options allows many of the SPI variants to be supported. Multimaster operation +is also supported. A CRC can be generated and checked in hardware. + +@note Some JTAG pins need to be remapped if SPI is to be used. + +@note The I2S protocol shares the SPI hardware so the two protocols cannot be +used at the same time on the same peripheral. + +Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words, +LSB first. +@code + spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT, + SPI_CR1_LSBFIRST); + spi_write(SPI1, 0x55); // 8-bit write + spi_write(SPI1, 0xaa88); // 16-bit write + reg8 = spi_read(SPI1); // 8-bit read + reg16 = spi_read(SPI1); // 16-bit read +@endcode + +@todo need additional functions to aid ISRs in retrieving status + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/* + * SPI and I2S code. + * + * Examples: + * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT, + * SPI_CR1_LSBFIRST); + * spi_write(SPI1, 0x55); // 8-bit write + * spi_write(SPI1, 0xaa88); // 16-bit write + * reg8 = spi_read(SPI1); // 8-bit read + * reg16 = spi_read(SPI1); // 16-bit read + */ + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Configure the SPI as Master. + +The SPI peripheral is configured as a master with communication parameters +baudrate, crc length 8/16 bits, frame format lsb/msb first, clock polarity +and phase. The SPI enable, CRC enable and CRC next controls are not affected. +These must be controlled separately. + +@todo NSS pin handling. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] br Unsigned int32. Baudrate @ref spi_baudrate. +@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol. +@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha. +@param[in] crcl Unsigned int32. CRC length 8/16 bits @ref spi_crcl. +@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref +spi_lsbfirst. +@returns int. Error code. +*/ + +int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha, + uint32_t crcl, uint32_t lsbfirst) +{ + uint32_t reg32 = SPI_CR1(spi); + + /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */ + reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT; + + reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */ + + reg32 |= br; /* Set baud rate bits. */ + reg32 |= cpol; /* Set CPOL value. */ + reg32 |= cpha; /* Set CPHA value. */ + reg32 |= crcl; /* Set crc length (8 or 16 bits). */ + reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */ + + /* TODO: NSS pin handling. */ + + SPI_CR1(spi) = reg32; + + return 0; /* TODO */ +} + +void spi_send8(uint32_t spi, uint8_t data) +{ + /* Wait for transfer finished. */ + while (!(SPI_SR(spi) & SPI_SR_TXE)); + + /* Write data (8 or 16 bits, depending on DFF) into DR. */ + SPI_DR8(spi) = data; +} + +uint8_t spi_read8(uint32_t spi) +{ + /* Wait for transfer finished. */ + while (!(SPI_SR(spi) & SPI_SR_RXNE)); + + /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */ + return SPI_DR8(spi); +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set CRC length to 8 bits + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_crcl_8bit(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_CRCL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set CRC length to 16 bits + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_crcl_16bit(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_CRCL; +} + +void spi_set_data_size(uint32_t spi, uint16_t data_s) +{ + SPI_CR2(spi) = (SPI_CR2(spi) & ~SPI_CR2_DS_MASK) | + (data_s & SPI_CR2_DS_MASK); +} + +void spi_fifo_reception_threshold_8bit(uint32_t spi) +{ + SPI_CR2(spi) |= SPI_CR2_FRXTH; +} + +void spi_fifo_reception_threshold_16bit(uint32_t spi) +{ + SPI_CR2(spi) &= ~SPI_CR2_FRXTH; +} + +void spi_i2s_mode_spi_mode(uint32_t spi) +{ + SPI_I2SCFGR(spi) &= ~SPI_I2SCFGR_I2SMOD; +} + + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/spi_common_l1f124.c b/libopencm3/lib/stm32/common/spi_common_l1f124.c new file mode 100644 index 0000000..6345350 --- /dev/null +++ b/libopencm3/lib/stm32/common/spi_common_l1f124.c @@ -0,0 +1,137 @@ +/** @addtogroup spi_file + +@author @htmlonly © @endhtmlonly 2009 +Uwe Hermann +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +Devices can have up to three SPI peripherals. The common 4-wire full-duplex +mode of operation is supported, along with 3-wire variants using unidirectional +communication modes or half-duplex bidirectional communication. A variety of +options allows many of the SPI variants to be supported. Multimaster operation +is also supported. A CRC can be generated and checked in hardware. + +@note Some JTAG pins need to be remapped if SPI is to be used. + +@note The I2S protocol shares the SPI hardware so the two protocols cannot be +used at the same time on the same peripheral. + +Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words, +LSB first. +@code + spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, + SPI_CR1_LSBFIRST); + spi_write(SPI1, 0x55); // 8-bit write + spi_write(SPI1, 0xaa88); // 16-bit write + reg8 = spi_read(SPI1); // 8-bit read + reg16 = spi_read(SPI1); // 16-bit read +@endcode + +@todo need additional functions to aid ISRs in retrieving status + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/* + * SPI and I2S code. + * + * Examples: + * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, + * SPI_CR1_LSBFIRST); + * spi_write(SPI1, 0x55); // 8-bit write + * spi_write(SPI1, 0xaa88); // 16-bit write + * reg8 = spi_read(SPI1); // 8-bit read + * reg16 = spi_read(SPI1); // 16-bit read + */ + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Configure the SPI as Master. + +The SPI peripheral is configured as a master with communication parameters +baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity +and phase. The SPI enable, CRC enable and CRC next controls are not affected. +These must be controlled separately. + +@todo NSS pin handling. + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +@param[in] br Unsigned int32. Baudrate @ref spi_baudrate. +@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol. +@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha. +@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff. +@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref +spi_lsbfirst. +@returns int. Error code. +*/ + +int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha, + uint32_t dff, uint32_t lsbfirst) +{ + uint32_t reg32 = SPI_CR1(spi); + + /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */ + reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT; + + reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */ + + reg32 |= br; /* Set baud rate bits. */ + reg32 |= cpol; /* Set CPOL value. */ + reg32 |= cpha; /* Set CPHA value. */ + reg32 |= dff; /* Set data format (8 or 16 bits). */ + reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */ + + /* TODO: NSS pin handling. */ + + SPI_CR1(spi) = reg32; + + return 0; /* TODO */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Data Frame Format to 8 bits + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_dff_8bit(uint32_t spi) +{ + SPI_CR1(spi) &= ~SPI_CR1_DFF; +} + +/*---------------------------------------------------------------------------*/ +/** @brief SPI Set Data Frame Format to 16 bits + +@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base. +*/ + +void spi_set_dff_16bit(uint32_t spi) +{ + SPI_CR1(spi) |= SPI_CR1_DFF; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/common/timer_common_all.c b/libopencm3/lib/stm32/common/timer_common_all.c new file mode 100644 index 0000000..a1a4380 --- /dev/null +++ b/libopencm3/lib/stm32/common/timer_common_all.c @@ -0,0 +1,2177 @@ +/** @addtogroup timer_file + +@author @htmlonly © @endhtmlonly 2010 +Edward Cheeseman +@author @htmlonly © @endhtmlonly 2011 +Stephen Caudle + +@section tim_common Notes for All Timers + +This library supports the General Purpose and Advanced Control Timers for +the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics. + +The STM32 series have four general purpose timers (2-5), while some have +an additional two advanced timers (1,8), and some have two basic timers (6,7). +Some of the larger devices have additional general purpose timers (9-14). + +@todo Add timer DMA burst settings + +@section tim_api_ex Basic TIMER handling API. + +Enable the timer clock first. The timer mode sets the clock division ratio, the +count alignment (edge or centred) and count direction. Finally enable the +timer. + +The timer output compare block produces a signal that can be configured for +output to a pin or passed to other peripherals for use as a trigger. In all +cases the output compare mode must be set to define how the output responds to +a compare match, and the output must be enabled. If output to a pin is +required, enable the appropriate GPIO clock and set the pin to alternate output +mode. + +Example: Timer 2 with 2x clock divide, edge aligned and up counting. +@code + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM2EN); + timer_reset(TIM2); + timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT_MUL_2, + TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + ... + timer_set_period(TIM2, 1000); + timer_enable_counter(TIM2); +@endcode +Example: Timer 1 with PWM output, no clock divide and centre alignment. Set the +Output Compare mode to PWM and enable the output of channel 1. Note that for +the advanced timers the break functionality must be enabled before the signal +will appear at the output, even though break is not being used. This is in +addition to the normal output enable. Enable the alternate function clock (APB2 +only) and port A clock. Set ports A8 and A9 (timer 1 channel 1 compare outputs) +to alternate function push-pull outputs where the PWM output will appear. + +@code + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN | + RCC_APB2ENR_AFIOEN); + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8 | GPIO9); + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN); + timer_reset(TIM1); + timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_CENTER_1, + TIM_CR1_DIR_UP); + timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM2); + timer_enable_oc_output(TIM1, TIM_OC1); + timer_enable_break_main_output(TIM1); + timer_set_oc_value(TIM1, TIM_OC1, 200); + timer_set_period(TIM1, 1000); + timer_enable_counter(TIM1); +@endcode + +@todo input capture example + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* + * Basic TIMER handling API. + * + * Examples: + * timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT_MUL_2, + * TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP); + */ + +/**@{*/ + +#include +#include + +#define ADVANCED_TIMERS (defined(TIM1_BASE) || defined(TIM8_BASE)) + +#if defined(TIM8) +#define TIMER_IS_ADVANCED(periph) ((periph == TIM1) || (periph == TIM8)) +#else +#define TIMER_IS_ADVANCED(periph) (periph == TIM1) +#endif + +/*---------------------------------------------------------------------------*/ +/** @brief Reset a Timer. + +The counter and all its associated configuration registers are placed in the +reset condition. The reset is effected via the RCC peripheral reset system. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref + tim_reg_base (TIM9 .. TIM14 not yet supported here). +*/ + +void timer_reset(uint32_t timer_peripheral) +{ + switch (timer_peripheral) { +#if defined(TIM1_BASE) + case TIM1: + rcc_periph_reset_pulse(RST_TIM1); + break; +#endif + case TIM2: + rcc_periph_reset_pulse(RST_TIM2); + break; + case TIM3: + rcc_periph_reset_pulse(RST_TIM3); + break; +#if defined(TIM4_BASE) + case TIM4: + rcc_periph_reset_pulse(RST_TIM4); + break; +#endif +#if defined(TIM5_BASE) + case TIM5: + rcc_periph_reset_pulse(RST_TIM5); + break; +#endif + case TIM6: + rcc_periph_reset_pulse(RST_TIM6); + break; + case TIM7: + rcc_periph_reset_pulse(RST_TIM7); + break; +#if defined(TIM8_BASE) + case TIM8: + rcc_periph_reset_pulse(RST_TIM8); + break; +#endif +/* These timers are not supported in libopencm3 yet */ +/* + case TIM9: + rcc_periph_reset_pulse(RST_TIM9); + break; + case TIM10: + rcc_periph_reset_pulse(RST_TIM10); + break; + case TIM11: + rcc_periph_reset_pulse(RST_TIM11); + break; + case TIM12: + rcc_periph_reset_pulse(RST_TIM12); + break; + case TIM13: + rcc_periph_reset_pulse(RST_TIM13); + break; + case TIM14: + rcc_periph_reset_pulse(RST_TIM14); + break; +*/ + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Interrupts for a Timer + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt +enable bits to be set +*/ + +void timer_enable_irq(uint32_t timer_peripheral, uint32_t irq) +{ + TIM_DIER(timer_peripheral) |= irq; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Interrupts for a Timer. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt +enable bits to be cleared +*/ + +void timer_disable_irq(uint32_t timer_peripheral, uint32_t irq) +{ + TIM_DIER(timer_peripheral) &= ~irq; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Return Interrupt Source. + +Returns true if the specified interrupt flag (UIF, TIF or CCxIF, with BIF or +COMIF for advanced timers) was set and the interrupt was enabled. If the +specified flag is not an interrupt flag, the function returns false. + +@todo Timers 6-7, 9-14 have fewer interrupts, but invalid flags are not caught +here. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values. +@returns boolean: flag set. +*/ + +bool timer_interrupt_source(uint32_t timer_peripheral, uint32_t flag) +{ +/* flag not set or interrupt disabled or not an interrupt source */ + if (((TIM_SR(timer_peripheral) & + TIM_DIER(timer_peripheral) & flag) == 0) || + (flag > TIM_SR_BIF)) { + return false; + } +/* Only an interrupt source for advanced timers */ +#if ADVANCED_TIMERS + if ((flag == TIM_SR_BIF) || (flag == TIM_SR_COMIF)) { + return TIMER_IS_ADVANCED(timer_peripheral); + } +#endif + return true; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read a Status Flag. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values. +@returns boolean: flag set. +*/ + +bool timer_get_flag(uint32_t timer_peripheral, uint32_t flag) +{ + if ((TIM_SR(timer_peripheral) & flag) != 0) { + return true; + } + + return false; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear a Status Flag. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] flag Unsigned int32. @ref tim_sr_values. Status register flag. +*/ + +void timer_clear_flag(uint32_t timer_peripheral, uint32_t flag) +{ + TIM_SR(timer_peripheral) &= ~flag; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Timer Mode. + +The modes are: + +@li Clock divider ratio (to form the sampling clock for the input filters, +and the dead-time clock in the advanced timers 1 and 8) +@li Edge/centre alignment +@li Count direction + +The alignment and count direction are effective only for timers 1 to 5 and 8 +while the clock divider ratio is effective for all timers except 6,7 +The remaining timers are limited hardware timers which do not support these mode +settings. + +@note: When center alignment mode is selected, count direction is controlled by +hardware and cannot be written. The count direction setting has no effect +in this case. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base (TIM1, TIM2 ... TIM5, TIM8) +@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref +tim_x_cr1_cdr +@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms +@param[in] direction Unsigned int32. Count direction in bit 4,: @ref +tim_x_cr1_dir +*/ + +void timer_set_mode(uint32_t timer_peripheral, uint32_t clock_div, + uint32_t alignment, uint32_t direction) +{ + uint32_t cr1; + + cr1 = TIM_CR1(timer_peripheral); + + cr1 &= ~(TIM_CR1_CKD_CK_INT_MASK | TIM_CR1_CMS_MASK | TIM_CR1_DIR_DOWN); + + cr1 |= clock_div | alignment | direction; + + TIM_CR1(timer_peripheral) = cr1; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Input Filter and Dead-time Clock Divider Ratio. + +This forms the sampling clock for the input filters and the dead-time clock +in the advanced timers 1 and 8, by division from the timer clock. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref +tim_x_cr1_cdr +*/ + +void timer_set_clock_division(uint32_t timer_peripheral, uint32_t clock_div) +{ + clock_div &= TIM_CR1_CKD_CK_INT_MASK; + TIM_CR1(timer_peripheral) &= ~TIM_CR1_CKD_CK_INT_MASK; + TIM_CR1(timer_peripheral) |= clock_div; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Auto-Reload Buffering. + +During counter operation this causes the counter to be loaded from its +auto-reload register only at the next update event. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_enable_preload(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_ARPE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Auto-Reload Buffering. + +This causes the counter to be loaded immediately with a new count value when the +auto-reload register is written, so that the new value becomes effective for the +current count cycle rather than for the cycle following an update event. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_disable_preload(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_ARPE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Specify the counter alignment mode. + +The mode can be edge aligned or centered. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms +*/ + +void timer_set_alignment(uint32_t timer_peripheral, uint32_t alignment) +{ + alignment &= TIM_CR1_CMS_MASK; + TIM_CR1(timer_peripheral) &= ~TIM_CR1_CMS_MASK; + TIM_CR1(timer_peripheral) |= alignment; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Timer to Count Up. + +This has no effect if the timer is set to center aligned. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_direction_up(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_DIR_DOWN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Timer to Count Down. + +This has no effect if the timer is set to center aligned. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_direction_down(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_DIR_DOWN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the Timer for One Cycle and Stop. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_one_shot_mode(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_OPM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the Timer to Run Continuously. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_continuous_mode(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_OPM; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Timer to Generate Update IRQ or DMA on any Event. + +The events which will generate an interrupt or DMA request can be +@li a counter underflow/overflow, +@li a forced update, +@li an event from the slave mode controller. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_update_on_any(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_URS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Timer to Generate Update IRQ or DMA only from Under/Overflow +Events. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_update_on_overflow(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_URS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Timer Update Events. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_enable_update_event(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_UDIS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Timer Update Events. + +Update events are not generated and the shadow registers keep their values. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_disable_update_event(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_UDIS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the timer to start counting. + +This should be called after the timer initial configuration has been completed. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_enable_counter(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) |= TIM_CR1_CEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Stop the timer from counting. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_disable_counter(uint32_t timer_peripheral) +{ + TIM_CR1(timer_peripheral) &= ~TIM_CR1_CEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer Output Idle States High. + +This determines the value of the timer output compare when it enters idle state. + +@sa @ref timer_set_oc_idle_state_set + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref +tim_x_cr2_ois. If several settings are to be made, use the logical OR of the +output control values. +*/ + +void timer_set_output_idle_state(uint32_t timer_peripheral, uint32_t outputs) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK; + } +#else + (void)timer_peripheral; + (void)outputs; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer Output Idle States Low. + +This determines the value of the timer output compare when it enters idle state. + +@sa @ref timer_set_oc_idle_state_unset + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref +tim_x_cr2_ois +*/ + +void timer_reset_output_idle_state(uint32_t timer_peripheral, uint32_t outputs) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK); + } +#else + (void)timer_peripheral; + (void)outputs; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer 1 Input to XOR of Three Channels. + +The first timer capture input is formed from the XOR of the first three timer +input channels 1, 2, 3. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_set_ti1_ch123_xor(uint32_t timer_peripheral) +{ + TIM_CR2(timer_peripheral) |= TIM_CR2_TI1S; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer 1 Input to Channel 1. + +The first timer capture input is taken from the timer input channel 1 only. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_set_ti1_ch1(uint32_t timer_peripheral) +{ + TIM_CR2(timer_peripheral) &= ~TIM_CR2_TI1S; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Master Mode + +This sets the Trigger Output TRGO for synchronizing with slave timers or +passing as an internal trigger to the ADC or DAC. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] mode Unsigned int32. Master Mode @ref tim_mastermode +*/ + +void timer_set_master_mode(uint32_t timer_peripheral, uint32_t mode) +{ + TIM_CR2(timer_peripheral) &= ~TIM_CR2_MMS_MASK; + TIM_CR2(timer_peripheral) |= mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer DMA Requests on Capture/Compare Events. + +Capture/compare events will cause DMA requests to be generated. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_set_dma_on_compare_event(uint32_t timer_peripheral) +{ + TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer DMA Requests on Update Events. + +Update events will cause DMA requests to be generated. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_set_dma_on_update_event(uint32_t timer_peripheral) +{ + TIM_CR2(timer_peripheral) |= TIM_CR2_CCDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Timer Capture/Compare Control Update with Trigger. + +If the capture/compare control bits CCxE, CCxNE and OCxM are set to be +preloaded, they are updated by software generating the COMG event (@ref +timer_generate_event) or when a rising edge occurs on the trigger input TRGI. + +@note This setting is only valid for the advanced timer channels with +complementary outputs. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_enable_compare_control_update_on_trigger(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Timer Capture/Compare Control Update with Trigger. + +If the capture/compare control bits CCxE, CCxNE and OCxM are set to be +preloaded, they are updated by software generating the COMG event (@ref +timer_generate_event). + +@note This setting is only valid for the advanced timer channels with +complementary outputs. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_disable_compare_control_update_on_trigger(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Timer Capture/Compare Control Preload. + +The capture/compare control bits CCxE, CCxNE and OCxM are set to be preloaded +when a COM event occurs. + +@note This setting is only valid for the advanced timer channels with +complementary outputs. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_enable_preload_complementry_enable_bits(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Timer Capture/Compare Control Preload. + +The capture/compare control bits CCxE, CCxNE and OCxM preload is disabled. + +@note This setting is only valid for the advanced timer channels with +complementary outputs. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +*/ + +void timer_disable_preload_complementry_enable_bits(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Value for the Timer Prescaler. + +The timer clock is prescaled by the 16 bit scale value plus 1. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] value Unsigned int32. Prescaler values 0...0xFFFF. +*/ + +void timer_set_prescaler(uint32_t timer_peripheral, uint32_t value) +{ + TIM_PSC(timer_peripheral) = value; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Value for the Timer Repetition Counter. + +A timer update event is generated only after the specified number of repeat +count cycles have been completed. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] value Unsigned int32. Repetition values 0...0xFF. +*/ + +void timer_set_repetition_counter(uint32_t timer_peripheral, uint32_t value) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_RCR(timer_peripheral) = value; + } +#else + (void)timer_peripheral; + (void)value; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set Period + +Specify the timer period in the auto-reload register. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] period Unsigned int32. Period in counter clock ticks. +*/ + +void timer_set_period(uint32_t timer_peripheral, uint32_t period) +{ + TIM_ARR(timer_peripheral) = period; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Enable the Output Compare Clear Function + +When this is enabled, the output compare signal is cleared when a high is +detected on the external trigger input. This works in the output compare and +PWM modes only (not forced mode). +The output compare signal remains off until the next update event. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +*/ + +void timer_enable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1CE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2CE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3CE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4CE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as oc clear enable only applies to the whole + * channel. + */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Disable the Output Compare Clear Function + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +*/ + +void timer_disable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1CE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2CE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3CE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4CE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as oc clear enable only applies to the whole + * channel. + */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Enable the Output Compare Fast Mode + +When this is enabled, the output compare signal is forced to the compare state +by a trigger input, independently of the compare match. This speeds up the +setting of the output compare to 3 clock cycles as opposed to at least 5 in the +slow mode. This works in the PWM1 and PWM2 modes only. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +*/ + +void timer_set_oc_fast_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1FE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2FE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3FE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4FE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as fast enable only applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Enable the Output Compare Slow Mode + +This disables the fast compare mode and the output compare depends on the +counter and compare register values. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +*/ + +void timer_set_oc_slow_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1FE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2FE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3FE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4FE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set Output Compare Mode + +Specifies how the comparator output will respond to a compare match. The mode +can be: +@li Frozen - the output does not respond to a match. +@li Active - the output assumes the active state on the first match. +@li Inactive - the output assumes the inactive state on the first match. +@li Toggle - The output switches between active and inactive states on each +match. +@li Force inactive. The output is forced low regardless of the compare state. +@li Force active. The output is forced high regardless of the compare state. +@li PWM1 - The output is active when the counter is less than the compare +register contents and inactive otherwise. +@li PWM2 - The output is inactive when the counter is less than the compare +register contents and active otherwise. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +@param[in] oc_mode enum ::tim_oc_mode. OC mode designators. + TIM_OCM_FROZEN, TIM_OCM_ACTIVE, TIM_OCM_INACTIVE, + TIM_OCM_TOGGLE, TIM_OCM_FORCE_LOW, TIM_OCM_FORCE_HIGH, + TIM_OCM_PWM1, TIM_OCM_PWM2 +*/ + +void timer_set_oc_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id, + enum tim_oc_mode oc_mode) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK; + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC1S_OUT; + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1M_MASK; + switch (oc_mode) { + case TIM_OCM_FROZEN: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FROZEN; + break; + case TIM_OCM_ACTIVE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_ACTIVE; + break; + case TIM_OCM_INACTIVE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_INACTIVE; + break; + case TIM_OCM_TOGGLE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_TOGGLE; + break; + case TIM_OCM_FORCE_LOW: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FORCE_LOW; + break; + case TIM_OCM_FORCE_HIGH: + TIM_CCMR1(timer_peripheral) |= + TIM_CCMR1_OC1M_FORCE_HIGH; + break; + case TIM_OCM_PWM1: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM1; + break; + case TIM_OCM_PWM2: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM2; + break; + } + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK; + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC2S_OUT; + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2M_MASK; + switch (oc_mode) { + case TIM_OCM_FROZEN: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FROZEN; + break; + case TIM_OCM_ACTIVE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_ACTIVE; + break; + case TIM_OCM_INACTIVE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_INACTIVE; + break; + case TIM_OCM_TOGGLE: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_TOGGLE; + break; + case TIM_OCM_FORCE_LOW: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FORCE_LOW; + break; + case TIM_OCM_FORCE_HIGH: + TIM_CCMR1(timer_peripheral) |= + TIM_CCMR1_OC2M_FORCE_HIGH; + break; + case TIM_OCM_PWM1: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM1; + break; + case TIM_OCM_PWM2: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM2; + break; + } + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK; + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC3S_OUT; + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3M_MASK; + switch (oc_mode) { + case TIM_OCM_FROZEN: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FROZEN; + break; + case TIM_OCM_ACTIVE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_ACTIVE; + break; + case TIM_OCM_INACTIVE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_INACTIVE; + break; + case TIM_OCM_TOGGLE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_TOGGLE; + break; + case TIM_OCM_FORCE_LOW: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FORCE_LOW; + break; + case TIM_OCM_FORCE_HIGH: + TIM_CCMR2(timer_peripheral) |= + TIM_CCMR2_OC3M_FORCE_HIGH; + break; + case TIM_OCM_PWM1: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM1; + break; + case TIM_OCM_PWM2: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM2; + break; + } + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK; + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC4S_OUT; + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4M_MASK; + switch (oc_mode) { + case TIM_OCM_FROZEN: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FROZEN; + break; + case TIM_OCM_ACTIVE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_ACTIVE; + break; + case TIM_OCM_INACTIVE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_INACTIVE; + break; + case TIM_OCM_TOGGLE: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_TOGGLE; + break; + case TIM_OCM_FORCE_LOW: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FORCE_LOW; + break; + case TIM_OCM_FORCE_HIGH: + TIM_CCMR2(timer_peripheral) |= + TIM_CCMR2_OC4M_FORCE_HIGH; + break; + case TIM_OCM_PWM1: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM1; + break; + case TIM_OCM_PWM2: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM2; + break; + } + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Enable the Output Compare Preload Register + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +*/ + +void timer_enable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1PE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2PE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3PE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4PE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Disable the Output Compare Preload Register + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action) +*/ + +void timer_disable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1PE; + break; + case TIM_OC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2PE; + break; + case TIM_OC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3PE; + break; + case TIM_OC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4PE; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set the Output Polarity High + +The polarity of the channel output is set active high. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_set_oc_polarity_high(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1P; + break; + case TIM_OC2: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2P; + break; + case TIM_OC3: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3P; + break; + case TIM_OC4: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4P; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to TIM1 and TIM8 only. */ + break; + } + + /* Acting for TIM1 and TIM8 only from here onwards. */ +#if ADVANCED_TIMERS + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } +#else + return; +#endif + + switch (oc_id) { + case TIM_OC1N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NP; + break; + case TIM_OC2N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NP; + break; + case TIM_OC3N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NP; + break; + case TIM_OC1: + case TIM_OC2: + case TIM_OC3: + case TIM_OC4: + /* Ignoring as this option was already set above. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set the Output Polarity Low + +The polarity of the channel output is set active low. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_set_oc_polarity_low(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC1P; + break; + case TIM_OC2: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC2P; + break; + case TIM_OC3: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC3P; + break; + case TIM_OC4: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC4P; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to TIM1 and TIM8 only. */ + break; + } + + /* Acting for TIM1 and TIM8 only from here onwards. */ +#if ADVANCED_TIMERS + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } +#else + return; +#endif + + switch (oc_id) { + case TIM_OC1N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NP; + break; + case TIM_OC2N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NP; + break; + case TIM_OC3N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NP; + break; + case TIM_OC1: + case TIM_OC2: + case TIM_OC3: + case TIM_OC4: + /* Ignoring as this option was already set above. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Enable the Output Compare + +The channel output compare functionality is enabled. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_enable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC1E; + break; + case TIM_OC2: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC2E; + break; + case TIM_OC3: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC3E; + break; + case TIM_OC4: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC4E; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to TIM1 and TIM8 only. */ + break; + } + + /* Acting for TIM1 and TIM8 only from here onwards. */ +#if ADVANCED_TIMERS + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } +#else + return; +#endif + + switch (oc_id) { + case TIM_OC1N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NE; + break; + case TIM_OC2N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NE; + break; + case TIM_OC3N: + TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NE; + break; + case TIM_OC1: + case TIM_OC2: + case TIM_OC3: + case TIM_OC4: + /* Ignoring as this option was already set above. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Disable the Output Compare + +The channel output compare functionality is disabled. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_disable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1E; + break; + case TIM_OC2: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2E; + break; + case TIM_OC3: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3E; + break; + case TIM_OC4: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4E; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to TIM1 and TIM8 only. */ + break; + } + + /* Acting for TIM1 and TIM8 only from here onwards. */ +#if ADVANCED_TIMERS + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } +#else + return; +#endif + + switch (oc_id) { + case TIM_OC1N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NE; + break; + case TIM_OC2N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NE; + break; + case TIM_OC3N: + TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NE; + break; + case TIM_OC1: + case TIM_OC2: + case TIM_OC3: + case TIM_OC4: + /* Ignoring as this option was already set above. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer set Output Compare Idle State High + +@sa Similar function suitable for multiple OC idle state settings +@ref timer_set_output_idle_state + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_set_oc_idle_state_set(uint32_t timer_peripheral, + enum tim_oc_id oc_id) +{ +#if ADVANCED_TIMERS + /* Acting for TIM1 and TIM8 only. */ + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } + + switch (oc_id) { + case TIM_OC1: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1; + break; + case TIM_OC1N: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1N; + break; + case TIM_OC2: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2; + break; + case TIM_OC2N: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2N; + break; + case TIM_OC3: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3; + break; + case TIM_OC3N: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3N; + break; + case TIM_OC4: + TIM_CR2(timer_peripheral) |= TIM_CR2_OIS4; + break; + } +#else + (void)timer_peripheral; + (void)oc_id; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set Output Compare Idle State Low + +@sa Similar function suitable for multiple OC idle state settings +@ref timer_reset_output_idle_state + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref +tim_reg_base +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced + timers 1 and 8) +*/ + +void timer_set_oc_idle_state_unset(uint32_t timer_peripheral, + enum tim_oc_id oc_id) +{ +#if ADVANCED_TIMERS + /* Acting for TIM1 and TIM8 only. */ + if (!TIMER_IS_ADVANCED(timer_peripheral)) { + return; + } + + switch (oc_id) { + case TIM_OC1: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1; + break; + case TIM_OC1N: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1N; + break; + case TIM_OC2: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2; + break; + case TIM_OC2N: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2N; + break; + case TIM_OC3: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3; + break; + case TIM_OC3N: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3N; + break; + case TIM_OC4: + TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS4; + break; + } +#else + (void)timer_peripheral; + (void)oc_id; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Timer Set Output Compare Value + +This is a convenience function to set the OC preload register value for loading +to the compare register. + +@param[in] timer_peripheral Unsigned int32. Timer register address base @ref + tim_reg_base (TIM9 .. TIM14 not yet supported here). +@param[in] oc_id enum ::tim_oc_id OC channel designators + TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken) +@param[in] value Unsigned int32. Compare value. +*/ + +void timer_set_oc_value(uint32_t timer_peripheral, enum tim_oc_id oc_id, + uint32_t value) +{ + switch (oc_id) { + case TIM_OC1: + TIM_CCR1(timer_peripheral) = value; + break; + case TIM_OC2: + TIM_CCR2(timer_peripheral) = value; + break; + case TIM_OC3: + TIM_CCR3(timer_peripheral) = value; + break; + case TIM_OC4: + TIM_CCR4(timer_peripheral) = value; + break; + case TIM_OC1N: + case TIM_OC2N: + case TIM_OC3N: + /* Ignoring as this option applies to the whole channel. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Output in Break + +Enables the output in the Break feature of an advanced timer. This does not +enable the break functionality itself but only sets the Master Output Enable in +the Break and Deadtime Register. + +@note This setting is only valid for the advanced timers. + +@note It is necessary to call this function to enable the output on an advanced +timer even if break or deadtime features are not being used. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_enable_break_main_output(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Output in Break + +Disables the output in the Break feature of an advanced timer. This clears +the Master Output Enable in the Break and Deadtime Register. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_disable_break_main_output(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Automatic Output in Break + +Enables the automatic output feature of the Break function of an advanced +timer so that the output is re-enabled at the next update event following a +break event. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_enable_break_automatic_output(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Automatic Output in Break + +Disables the automatic output feature of the Break function of an advanced +timer so that the output is re-enabled at the next update event following a +break event. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_disable_break_automatic_output(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Activate Break when Input High + +Sets the break function to activate when the break input becomes high. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_break_polarity_high(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Activate Break when Input Low + +Sets the break function to activate when the break input becomes low. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_break_polarity_low(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Break + +Enables the break function of an advanced timer. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_enable_break(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Break + +Disables the break function of an advanced timer. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_disable_break(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Off-State in Run Mode + +Enables the off-state in run mode for the break function of an advanced +timer in which the complementary outputs have been configured. It has no effect +if no complementary output is present. When the capture-compare output is +disabled while the complementary output is enabled, the output is set to its +inactive level as defined by the output polarity. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_enabled_off_state_in_run_mode(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Off-State in Run Mode + +Disables the off-state in run mode for the break function of an advanced +timer in which the complementary outputs have been configured. It has no effect +if no complementary output is present. When the capture-compare output is +disabled, the output is also disabled. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_disabled_off_state_in_run_mode(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Off-State in Idle Mode + +Enables the off-state in idle mode for the break function of an advanced +timer. When the master output is disabled the output is set to its +inactive level as defined by the output polarity. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_enabled_off_state_in_idle_mode(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Off-State in Idle Mode + +Disables the off-state in idle mode for the break function of an advanced +timer. When the master output is disabled the output is also disabled. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +*/ + +void timer_set_disabled_off_state_in_idle_mode(uint32_t timer_peripheral) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI; + } +#else + (void)timer_peripheral; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Lock Bits + +Set the lock bits for an advanced timer. Three levels of lock providing +protection against software errors. Once written they cannot be changed until a +timer reset has occurred. + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +@param[in] lock Unsigned int32. Lock specification @ref tim_lock +*/ + +void timer_set_break_lock(uint32_t timer_peripheral, uint32_t lock) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= lock; + } +#else + (void)timer_peripheral; + (void)lock; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Deadtime + +The deadtime and sampling clock (DTSC) is set in the clock division ratio part +of the timer mode settings. The deadtime count is an 8 bit value defined in +terms of the number of DTSC cycles: + +@li Bit 7 = 0, deadtime = bits(6:0) +@li Bits 7:6 = 10, deadtime = 2x(64+bits(5:0)) +@li Bits 7:5 = 110, deadtime = 8x(32+bits(5:0)) +@li Bits 7:5 = 111, deadtime = 16x(32+bits(5:0)) + +@note This setting is only valid for the advanced timers. + +@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or +TIM8 +@param[in] deadtime Unsigned int32. Deadtime count specification as defined +above. +*/ + +void timer_set_deadtime(uint32_t timer_peripheral, uint32_t deadtime) +{ +#if ADVANCED_TIMERS + if (TIMER_IS_ADVANCED(timer_peripheral)) { + TIM_BDTR(timer_peripheral) |= deadtime; + } +#else + (void)timer_peripheral; + (void)deadtime; +#endif +} + +/*---------------------------------------------------------------------------*/ +/** @brief Force generate a timer event. + +The event specification consists of 8 possible events that can be forced on the +timer. The forced events are automatically cleared by hardware. The UG event is +useful to cause shadow registers to be preloaded before the timer is started to +avoid uncertainties in the first cycle in case an update event may never be +generated. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] event Unsigned int32. Event specification @ref tim_event_gen +*/ + +void timer_generate_event(uint32_t timer_peripheral, uint32_t event) +{ + TIM_EGR(timer_peripheral) |= event; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read Counter + +Read back the value of a timer's counter register contents + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@returns Unsigned int32. Counter value. +*/ + +uint32_t timer_get_counter(uint32_t timer_peripheral) +{ + return TIM_CNT(timer_peripheral); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Counter + +Set the value of a timer's counter register contents. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] count Unsigned int32. Counter value. +*/ + +void timer_set_counter(uint32_t timer_peripheral, uint32_t count) +{ + TIM_CNT(timer_peripheral) = count; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Input Capture Filter Parameters + +Set the input filter parameters for an input channel, specifying: +@li the frequency of sampling from the Deadtime and Sampling clock +(@see @ref timer_set_clock_division) +@li the number of events that must occur before a transition is considered +valid. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +@param[in] flt ::tim_ic_filter. Input Capture Filter identifier. +*/ + +void timer_ic_set_filter(uint32_t timer_peripheral, enum tim_ic_id ic, + enum tim_ic_filter flt) +{ + switch (ic) { + case TIM_IC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1F_MASK; + TIM_CCMR1(timer_peripheral) |= flt << 4; + break; + case TIM_IC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2F_MASK; + TIM_CCMR1(timer_peripheral) |= flt << 12; + break; + case TIM_IC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3F_MASK; + TIM_CCMR2(timer_peripheral) |= flt << 4; + break; + case TIM_IC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4F_MASK; + TIM_CCMR2(timer_peripheral) |= flt << 12; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Input Capture Prescaler + +Set the number of events between each capture. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler. +*/ + +void timer_ic_set_prescaler(uint32_t timer_peripheral, enum tim_ic_id ic, + enum tim_ic_psc psc) +{ + switch (ic) { + case TIM_IC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1PSC_MASK; + TIM_CCMR1(timer_peripheral) |= psc << 2; + break; + case TIM_IC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2PSC_MASK; + TIM_CCMR1(timer_peripheral) |= psc << 10; + break; + case TIM_IC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3PSC_MASK; + TIM_CCMR2(timer_peripheral) |= psc << 2; + break; + case TIM_IC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4PSC_MASK; + TIM_CCMR2(timer_peripheral) |= psc << 10; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Capture/Compare Channel Direction/Input + +The Capture/Compare channel is defined as output (compare) or input with the +input mapping specified: + +@li channel is configured as output +@li channel is configured as input and mapped on corresponding input +@li channel is configured as input and mapped on alternate input +(TI2 for channel 1, TI1 for channel 2, TI4 for channel 3, TI3 for channel 4) +@li channel is configured as input and is mapped on TRC (requires an +internal trigger input selected through TS bit + +@note not all combinations of the input and channel are valid, see datasheets. +@note these parameters are writable only when the channel is off. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +@param[in] in ::tim_ic_input. Input Capture channel direction and source input. +*/ + +void timer_ic_set_input(uint32_t timer_peripheral, enum tim_ic_id ic, + enum tim_ic_input in) +{ + in &= 3; + + if (((ic == TIM_IC2) || (ic == TIM_IC4)) && + ((in == TIM_IC_IN_TI1) || (in == TIM_IC_IN_TI2))) { + /* Input select bits are flipped for these combinations */ + in ^= 3; + } + + switch (ic) { + case TIM_IC1: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK; + TIM_CCMR1(timer_peripheral) |= in; + break; + case TIM_IC2: + TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK; + TIM_CCMR1(timer_peripheral) |= in << 8; + break; + case TIM_IC3: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK; + TIM_CCMR2(timer_peripheral) |= in; + break; + case TIM_IC4: + TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK; + TIM_CCMR2(timer_peripheral) |= in << 8; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable Timer Input Capture + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +*/ + +void timer_ic_enable(uint32_t timer_peripheral, enum tim_ic_id ic) +{ + TIM_CCER(timer_peripheral) |= (0x1 << (ic * 4)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable Timer Input Capture + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +*/ + +void timer_ic_disable(uint32_t timer_peripheral, enum tim_ic_id ic) +{ + TIM_CCER(timer_peripheral) &= ~(0x1 << (ic * 4)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set External Trigger Filter Parameters for Slave + +Set the input filter parameters for the external trigger, specifying: +@li the frequency of sampling from the Deadtime and Sampling clock +(@see @ref timer_set_clock_division) +@li the number of events that must occur before a transition is considered +valid. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] flt ::tim_ic_filter. Input Capture Filter identifier. +*/ + +void timer_slave_set_filter(uint32_t timer_peripheral, enum tim_ic_filter flt) +{ + TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETF_MASK; + TIM_SMCR(timer_peripheral) |= flt << 8; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set External Trigger Prescaler for Slave + +Set the external trigger frequency division ratio. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler. +*/ + +void timer_slave_set_prescaler(uint32_t timer_peripheral, enum tim_ic_psc psc) +{ + TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETPS_MASK; + TIM_SMCR(timer_peripheral) |= psc << 12; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set External Trigger Polarity for Slave + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] pol ::tim_et_pol. Slave External Trigger polarity. +*/ + +void timer_slave_set_polarity(uint32_t timer_peripheral, enum tim_et_pol pol) +{ + if (pol) { + TIM_SMCR(timer_peripheral) |= TIM_SMCR_ETP; + } else { + TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETP; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Slave Mode + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] mode Unsigned int8. Slave mode @ref tim_sms +*/ + +void timer_slave_set_mode(uint32_t timer_peripheral, uint8_t mode) +{ + TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_SMS_MASK; + TIM_SMCR(timer_peripheral) |= mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set Slave Trigger Source + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] trigger Unsigned int8. Slave trigger source @ref tim_ts +*/ + +void timer_slave_set_trigger(uint32_t timer_peripheral, uint8_t trigger) +{ + TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_TS_MASK; + TIM_SMCR(timer_peripheral) |= trigger; +} + +/* TODO Timer DMA burst */ + +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/timer_common_f234.c b/libopencm3/lib/stm32/common/timer_common_f234.c new file mode 100644 index 0000000..1506408 --- /dev/null +++ b/libopencm3/lib/stm32/common/timer_common_f234.c @@ -0,0 +1,58 @@ +/** @addtogroup timer_file + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set Input Polarity + +The timer channel must be set to input capture mode. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +@param[in] pol ::tim_ic_pol. Input Capture polarity control. +*/ + +void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic, + enum tim_ic_pol pol) +{ + /* Clear CCxP and CCxNP to zero. For both edge trigger both fields are + * set. Case 10 is invalid. + */ + TIM_CCER(timer_peripheral) &= ~(0xa << (ic * 4)); + switch (pol) { + case TIM_IC_RISING: /* 00 */ + break; + case TIM_IC_BOTH: /* 11 */ + TIM_CCER(timer_peripheral) |= (0xa << (ic * 4)); + break; + case TIM_IC_FALLING: /* 01 */ + TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4)); + } +} +/**@}*/ + + diff --git a/libopencm3/lib/stm32/common/timer_common_f24.c b/libopencm3/lib/stm32/common/timer_common_f24.c new file mode 100644 index 0000000..ce1c1e3 --- /dev/null +++ b/libopencm3/lib/stm32/common/timer_common_f24.c @@ -0,0 +1,53 @@ +/** @addtogroup timer_file + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer Option + +Set timer options register on TIM2 or TIM5, used for trigger remapping on TIM2, +and similarly for TIM5 for oscillator calibration purposes. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM5: +@ref tim5_opt_trigger_remap. +*/ + +void timer_set_option(uint32_t timer_peripheral, uint32_t option) +{ + if (timer_peripheral == TIM2) { + TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK; + TIM_OR(timer_peripheral) |= option; + } else if (timer_peripheral == TIM5) { + TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK; + TIM_OR(timer_peripheral) |= option; + } +} + +/**@}*/ + + diff --git a/libopencm3/lib/stm32/common/usart_common_all.c b/libopencm3/lib/stm32/common/usart_common_all.c new file mode 100644 index 0000000..43fd199 --- /dev/null +++ b/libopencm3/lib/stm32/common/usart_common_all.c @@ -0,0 +1,367 @@ +/** @addtogroup usart_file + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +This library supports the USART/UART in the STM32F series +of ARM Cortex Microcontrollers by ST Microelectronics. + +Devices can have up to 3 USARTs and 2 UARTs. + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Baudrate. + +The baud rate is computed from the APB high-speed prescaler clock (for +USART1/6) or the APB low-speed prescaler clock (for other USARTs). These values +must be correctly set before calling this function (refer to the +rcc_clock_setup-* functions in RCC). + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] baud unsigned 32 bit. Baud rate specified in Hz. +*/ + +void usart_set_baudrate(uint32_t usart, uint32_t baud) +{ + uint32_t clock = rcc_ppre1_frequency; + +#if defined STM32F2 || defined STM32F4 + if ((usart == USART1) || + (usart == USART6)) { + clock = rcc_ppre2_frequency; + } +#else + if (usart == USART1) { + clock = rcc_ppre2_frequency; + } +#endif + + /* + * Yes it is as simple as that. The reference manual is + * talking about fractional calculation but it seems to be only + * marketting babble to sound awesome. It is nothing else but a + * simple divider to generate the correct baudrate. + * + * Note: We round() the value rather than floor()ing it, for more + * accurate divisor selection. + */ + USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Word Length. + +The word length is set to 8 or 9 bits. Note that the last bit will be a parity +bit if parity is enabled, in which case the data length will be 7 or 8 bits +respectively. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] bits unsigned 32 bit. Word length in bits 8 or 9. +*/ + +void usart_set_databits(uint32_t usart, uint32_t bits) +{ + if (bits == 8) { + USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */ + } else { + USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */ + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Stop Bit(s). + +The stop bits are specified as 0.5, 1, 1.5 or 2. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits. +*/ + +void usart_set_stopbits(uint32_t usart, uint32_t stopbits) +{ + uint32_t reg32; + + reg32 = USART_CR2(usart); + reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits; + USART_CR2(usart) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Parity. + +The parity bit can be selected as none, even or odd. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity. +*/ + +void usart_set_parity(uint32_t usart, uint32_t parity) +{ + uint32_t reg32; + + reg32 = USART_CR1(usart); + reg32 = (reg32 & ~USART_PARITY_MASK) | parity; + USART_CR1(usart) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Rx/Tx Mode. + +The mode can be selected as Rx only, Tx only or Rx+Tx. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode. +*/ + +void usart_set_mode(uint32_t usart, uint32_t mode) +{ + uint32_t reg32; + + reg32 = USART_CR1(usart); + reg32 = (reg32 & ~USART_MODE_MASK) | mode; + USART_CR1(usart) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Hardware Flow Control. + +The flow control bit can be selected as none, RTS, CTS or RTS+CTS. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol. +*/ + +void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol) +{ + uint32_t reg32; + + reg32 = USART_CR3(usart); + reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol; + USART_CR3(usart) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Enable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_UE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Disable. + +At the end of the current frame, the USART is disabled to reduce power. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_UE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Send Data Word with Blocking + +Blocks until the transmit data buffer becomes empty then writes the next data +word for transmission. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] data unsigned 16 bit. +*/ + +void usart_send_blocking(uint32_t usart, uint16_t data) +{ + usart_wait_send_ready(usart); + usart_send(usart, data); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Received Data Word with Blocking. + +Wait until a data word has been received then return the word. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@returns unsigned 16 bit data word. +*/ + +uint16_t usart_recv_blocking(uint32_t usart) +{ + usart_wait_recv_ready(usart); + + return usart_recv(usart); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver DMA Enable. + +DMA is available on: +@li USART1 Rx DMA1 channel 5. +@li USART2 Rx DMA1 channel 6. +@li USART3 Rx DMA1 channel 3. +@li UART4 Rx DMA2 channel 3. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_rx_dma(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_DMAR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver DMA Disable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable_rx_dma(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_DMAR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter DMA Enable. + +DMA is available on: +@li USART1 Tx DMA1 channel 4. +@li USART2 Tx DMA1 channel 7. +@li USART3 Tx DMA1 channel 2. +@li UART4 Tx DMA2 channel 5. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_tx_dma(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_DMAT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter DMA Disable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable_tx_dma(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_DMAT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver Interrupt Enable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_rx_interrupt(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_RXNEIE; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver Interrupt Disable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable_rx_interrupt(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_RXNEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter Interrupt Enable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_tx_interrupt(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter Interrupt Disable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable_tx_interrupt(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Error Interrupt Enable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_error_interrupt(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_EIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Error Interrupt Disable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_disable_error_interrupt(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_EIE; +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/common/usart_common_f124.c b/libopencm3/lib/stm32/common/usart_common_f124.c new file mode 100644 index 0000000..ea5b4ee --- /dev/null +++ b/libopencm3/lib/stm32/common/usart_common_f124.c @@ -0,0 +1,143 @@ +/** @addtogroup usart_file + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +This library supports the USART/UART in the STM32F series +of ARM Cortex Microcontrollers by ST Microelectronics. + +Devices can have up to 3 USARTs and 2 UARTs. + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @brief USART Send a Data Word. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] data unsigned 16 bit. +*/ + +void usart_send(uint32_t usart, uint16_t data) +{ + /* Send data. */ + USART_DR(usart) = (data & USART_DR_MASK); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Received Data Word. + +If parity is enabled the MSB (bit 7 or 8 depending on the word length) is the +parity bit. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@returns unsigned 16 bit data word. +*/ + +uint16_t usart_recv(uint32_t usart) +{ + /* Receive data. */ + return USART_DR(usart) & USART_DR_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Transmit Data Buffer Empty + +Blocks until the transmit data buffer becomes empty and is ready to accept the +next data word. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_wait_send_ready(uint32_t usart) +{ + /* Wait until the data has been transferred into the shift register. */ + while ((USART_SR(usart) & USART_SR_TXE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Received Data Available + +Blocks until the receive data buffer holds a valid received data word. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_wait_recv_ready(uint32_t usart) +{ + /* Wait until the data is ready to be received. */ + while ((USART_SR(usart) & USART_SR_RXNE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Status Flag. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. +@returns boolean: flag set. +*/ + +bool usart_get_flag(uint32_t usart, uint32_t flag) +{ + return ((USART_SR(usart) & flag) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Return Interrupt Source. + +Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was +set and the interrupt was enabled. If the specified flag is not an interrupt +flag, the function returns false. + +@todo These are the most important interrupts likely to be used. Others +relating to LIN break, and error conditions in multibuffer communication, need +to be added for completeness. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. +@returns boolean: flag and interrupt enable both set. +*/ + +bool usart_get_interrupt_source(uint32_t usart, uint32_t flag) +{ + uint32_t flag_set = (USART_SR(usart) & flag); + /* IDLE, RXNE, TC, TXE interrupts */ + if ((flag >= USART_SR_IDLE) && (flag <= USART_SR_TXE)) { + return ((flag_set & USART_CR1(usart)) != 0); + /* Overrun error */ + } else if (flag == USART_SR_ORE) { + return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE); + } + + return false; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/desig.c b/libopencm3/lib/stm32/desig.c new file mode 100644 index 0000000..b610e66 --- /dev/null +++ b/libopencm3/lib/stm32/desig.c @@ -0,0 +1,54 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +uint16_t desig_get_flash_size(void) +{ + return DESIG_FLASH_SIZE; +} + +void desig_get_unique_id(uint32_t result[]) +{ + result[0] = DESIG_UNIQUE_ID2; + result[1] = DESIG_UNIQUE_ID1; + result[2] = DESIG_UNIQUE_ID0; +} + +void desig_get_unique_id_as_string(char *string, + unsigned int string_len) +{ + int i, len; + uint8_t device_id[12]; + static const char chars[] = "0123456789ABCDEF"; + + desig_get_unique_id((uint32_t *)device_id); + + /* Each byte produces two characters */ + len = (2 * sizeof(device_id) < string_len) ? + 2 * sizeof(device_id) : string_len - 1; + + for (i = 0; i < len; i += 2) { + string[i] = chars[(device_id[i / 2] >> 0) & 0x0F]; + string[i + 1] = chars[(device_id[i / 2] >> 4) & 0x0F]; + } + + string[len] = '\0'; +} + diff --git a/libopencm3/lib/stm32/f0/Makefile b/libopencm3/lib/stm32/f0/Makefile new file mode 100644 index 0000000..156171c --- /dev/null +++ b/libopencm3/lib/stm32/f0/Makefile @@ -0,0 +1,49 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2013 Frantisek Burian +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32f0 +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi +#PREFIX ?= arm-elf +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m0 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32F0 + +ARFLAGS = rcs + +OBJS = flash.o rcc.o usart.o dma.o rtc.o comparator.o crc.o \ + dac.o i2c.o iwdg.o pwr.o gpio.o timer.o adc.o + +OBJS += gpio_common_all.o gpio_common_f0234.o crc_common_all.o \ + pwr_common_all.o iwdg_common_all.o rtc_common_l1f024.o \ + dma_common_l1f013.o exti_common_all.o spi_common_all.o \ + spi_common_f03.o flash_common_f01.o dac_common_all.o \ + timer_common_all.o + +VPATH += ../../usb:../:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/stm32/f0/adc.c b/libopencm3/lib/stm32/f0/adc.c new file mode 100644 index 0000000..7dbf84a --- /dev/null +++ b/libopencm3/lib/stm32/f0/adc.c @@ -0,0 +1,835 @@ +/** @defgroup adc_file ADC + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Analog to Digital Converters + * + * based on F3 file + * + * @date 14 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_opmode ADC Operation mode API + * @ingroup adc_file + * + * @brief ADC Result API + * + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Continuous Conversion Mode + * + * In this mode the ADC starts a new conversion of a single channel or a channel + * group immediately following completion of the previous channel group + * conversion. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_set_continuous_conversion_mode(uint32_t adc) +{ + ADC_CFGR1(adc) |= ADC_CFGR1_CONT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Single Conversion Mode + * + * In this mode the ADC performs a conversion of one channel or a channel group + * and stops. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_set_single_conversion_mode(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Discontinuous Mode for Regular Conversions + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_discontinuous_mode(uint32_t adc) +{ + ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Discontinuous Mode for Regular Conversions + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_discontinuous_mode(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** ADC Set operation mode + * + * There are some operation modes, common for entire stm32 branch. In the text + * the braces are describing result to single trigger event. The trigger event + * is described by character T in the description. The ADC is configured to + * convert list of inputs [0, 1, 2, 3]. In Grouped modes, there is used group + * size of 2 conversions in the examples + * + * @li @c ADC_MODE_SEQUENTIAL: T(0) T(1) T(2) T(3)[EOSEQ] T(0) T(1) T(2) ... + * + * In this mode, after the trigger event a single channel is converted and the + * next channel in the list is prepared to convert on next trigger edge. + * + * @note This mode can be emulated by ADC_MODE_GROUPED with group size + * of 1. @par + * + * @li @c ADC_MODE_SCAN: T(0123)[EOSEQ] T(0123)[EOSEQ] T(0123)[EOSEQ] + * + * In this mode, after the trigger event, all channels will be converted once, + * storing results sequentially. + * + * @note The DMA must be configured properly for more than single channel to + * convert. @par + * + * @li @c ADC_MODE_SCAN_INFINITE: T(0123[EOSEQ]0123[EOSEQ]0123[EOSEQ]...) + * + * In this mode, after the trigger event, all channels from the list are + * converted. At the end of list, the conversion continues from the beginning. + * + * @note The DMA must be configured properly to operate in this mode.@par + * + * @li @c ADC_MODE_GROUPED: T(12) T(34)[EOSEQ] T(12) T(34)[EOSEQ] T(12) + * + * In this mode, after the trigger event, a specified group size of channels + * are converted. If the end of channel list occurs, the EOSEQ is generated + * and on the next trigger it wraps to the beginning. + * + * @note The DMA must be configured properly to operate on more than single + * channel conversion groups.@par + * + * @warning not all families supports all modes of operation of ADC. + * + * @par + * + */ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set conversion operation mode + * + * @note on SEQUENTIAL mode, the trigger event is neccesary to start conversion. + * @par + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] adc ::adc_opmode. ADC operation mode (@ref adc_opmode) + */ + +void adc_set_operation_mode(uint32_t adc, enum adc_opmode opmode) +{ + switch (opmode) { + case ADC_MODE_SEQUENTIAL: + ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT; + ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN; + break; + + case ADC_MODE_SCAN: + ADC_CFGR1(adc) &= ~(ADC_CFGR1_CONT | ADC_CFGR1_DISCEN); + break; + + case ADC_MODE_SCAN_INFINITE: + ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN; + ADC_CFGR1(adc) |= ADC_CFGR1_CONT; + break; + } +} + +/**@}*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_result ADC Result API + * @ingroup adc_file + * + * @brief ADC Result API + * + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Software Triggered Conversion on Regular Channels + * + * This starts conversion on a set of defined regular channels. It is cleared + * by hardware once conversion starts. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_start_conversion_regular(uint32_t adc) +{ + /* Start conversion on regular channels. */ + ADC_CR(adc) |= ADC_CR_ADSTART; + + /* Wait until the ADC starts the conversion. */ + while (ADC_CR(adc) & ADC_CR_ADSTART); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the End-of-Conversion Flag + * + * This flag is set after all channels of a regular or injected group have been + * converted. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @returns bool. End of conversion flag. + */ + +bool adc_eoc(uint32_t adc) +{ + return ((ADC_ISR(adc) & ADC_ISR_EOC) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read from the Regular Conversion Result Register + * + * The result read back is 12 bits, right or left aligned within the first + * 16 bits. For ADC1 only, the higher 16 bits will hold the result from ADC2 if + * an appropriate dual mode has been set @see adc_set_dual_mode. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @returns Unsigned int32 conversion result. + */ + +uint32_t adc_read_regular(uint32_t adc) +{ + return ADC_DR(adc); +} + +/**@}*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_trigger ADC Trigger API + * @ingroup adc_file + * + * @brief ADC Trigger API + * + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Regular Channels + * + * This enables an external trigger for set of defined regular channels, and + * sets the polarity of the trigger event: rising or falling edge or both. Note + * that if the trigger polarity is zero, triggering is disabled. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] trigger Unsigned int32. Trigger identifier + * @ref adc_trigger_regular + * @param[in] polarity Unsigned int32. Trigger polarity @ref + * adc_trigger_polarity_regular + */ + +void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTSEL) | trigger; + ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTEN) | polarity; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Regular Channels + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_external_trigger_regular(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_EXTEN; +} + +/**@}*/ + + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_interrupts ADC Interrupt configuration API + * @ingroup adc_file + * + * @brief ADC Interrupt configuration API + * + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_watchdog_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_AWDIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Regular End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_watchdog_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_AWDIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Analog Watchdog Flag + * + * This flag is set when the converted voltage crosses the high or low + * thresholds. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @returns bool true, if the signal is out of defined analog range. + */ + +bool adc_get_watchdog_flag(uint32_t adc) +{ + return ADC_ISR(adc) & ADC_ISR_AWD; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Clear Analog Watchdog Flag + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_clear_watchdog_flag(uint32_t adc) +{ + ADC_ISR(adc) = ADC_ISR_AWD; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable the Overrun Interrupt + * + * The overrun interrupt is generated when data is not read from a result + * register before the next conversion is written. If DMA is enabled, all + * transfers are terminated and any conversion sequence is aborted. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_overrun_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable the Overrun Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_overrun_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Overrun Flag + * + * The overrun flag is set when data is not read from a result register before + * the next conversion is written. If DMA is enabled, all transfers are + * terminated and any conversion sequence is aborted. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +bool adc_get_overrun_flag(uint32_t adc) +{ + return ADC_ISR(adc) & ADC_ISR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Clear Overrun Flags + * + * The overrun flag is cleared. Note that if an overrun occurs, DMA is + * terminated. + * The flag must be cleared and the DMA stream and ADC reinitialised to resume + * conversions (see the reference manual). + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_clear_overrun_flag(uint32_t adc) +{ + ADC_ISR(adc) = ADC_ISR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Regular End-Of-Conversion Sequence Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_eoc_sequence_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_EOSEQIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Regular End-Of-Conversion Sequence Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_eoc_sequence_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_EOSEQIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Regular End-Of-Conversion Sequence Flag + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +bool adc_get_eoc_sequence_flag(uint32_t adc) +{ + return ADC_ISR(adc) & ADC_ISR_EOSEQ; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Regular End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_eoc_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_EOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Regular End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_eoc_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_EOCIE; +} + +/**@}*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_config ADC Basic configuration API + * @ingroup adc_file + * + * @brief ADC Basic configuration API + * + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power Off + * + * Turn off the ADC to reduce power consumption to a few microamps. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_power_off(uint32_t adc) +{ + ADC_CR(adc) &= ~ADC_CR_ADEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + * + * If the ADC is in power-down mode then it is powered up. The application + * needs to wait a time of about 3 microseconds for stabilization before using + * the ADC. If the ADC is already on this function call will have no effect. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_power_on(uint32_t adc) +{ + ADC_CR(adc) |= ADC_CR_ADEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Clock Prescale + * + * The ADC clock taken from the many sources. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] prescale Unsigned int32. Prescale value (@ref adc_api_clksource) + */ + +void adc_set_clk_source(uint32_t adc, uint32_t source) +{ + ADC_CFGR2(adc) = ((ADC_CFGR2(adc) & ~ADC_CFGR2_CKMODE) | source); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set a Regular Channel Conversion Sequence + * + * Define a sequence of channels to be converted as a regular group with a + * length from 1 to 18 channels. If this is called during conversion, the + * current conversion is reset and conversion begins again with the newly + * defined group. + * + * @warning This core doesn't support the random order of ADC conversions. + * The channel list must be ordered by channel number. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] length Unsigned int8. Number of channels in the group. + * @param[in] channel Unsigned int8[]. Set of channels to convert, integers + * 0..18. + */ + +void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[]) +{ + uint32_t reg32 = 0; + uint8_t i = 0; + bool stepup = false, stepdn = false; + + if (length == 0) { + ADC_CHSELR(adc) = 0; + return; + } + + reg32 |= (1 << channel[0]); + + for (i = 1; i < length; i++) { + reg32 |= (1 << channel[i]); + stepup |= channel[i-1] < channel[i]; + stepdn |= channel[i-1] > channel[i]; + } + + /* Check, if the channel list is in order */ + if (stepup && stepdn) { + cm3_assert_not_reached(); + } + + /* Update the scan direction flag */ + if (stepdn) { + ADC_CFGR1(adc) |= ADC_CFGR1_SCANDIR; + } else { + ADC_CFGR1(adc) &= ~ADC_CFGR1_SCANDIR; + } + + ADC_CHSELR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for All Channels + * + * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, + * same for all channels. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] time Unsigned int8. Sampling time selection (@ref adc_api_smptime) + */ + +void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time) +{ + ADC_SMPR(adc) = time & ADC_SMPR_SMP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Resolution + * + * ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a + * corresponding reduction in conversion time. + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] resolution Unsigned int16. Resolution value (@ref adc_api_res) + */ + +void adc_set_resolution(uint32_t adc, uint16_t resolution) +{ + ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_RES) | resolution; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Left Aligned + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_set_left_aligned(uint32_t adc) +{ + ADC_CFGR1(adc) |= ADC_CFGR1_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Right Aligned + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_set_right_aligned(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable DMA Transfers + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_dma(uint32_t adc) +{ + ADC_CFGR1(adc) |= ADC_CFGR1_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable DMA Transfers + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_disable_dma(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The Temperature Sensor + * + * This enables the sensor on channel 16 + */ + +void adc_enable_temperature_sensor(void) +{ + ADC_CCR |= ADC_CCR_TSEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The Temperature Sensor + * + * Disabling this will reduce power consumption from the temperature sensor + * measurement. + */ + +void adc_disable_temperature_sensor(void) +{ + ADC_CCR &= ~ADC_CCR_TSEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The VRef Sensor + * + * This enables the reference voltage measurements on channel 17. + */ + +void adc_enable_vref_sensor(void) +{ + ADC_CCR |= ADC_CCR_VREFEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The VRef Sensor + * + * Disabling this will reduce power consumption from the reference voltage + * measurement. + */ + +void adc_disable_vref_sensor(void) +{ + ADC_CCR &= ~ADC_CCR_VREFEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The VBat Sensor + * + * This enables the battery voltage measurements on channel 17. + */ + +void adc_enable_vbat_sensor(void) +{ + ADC_CCR |= ADC_CCR_VBATEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The VBat Sensor + * + * Disabling this will reduce power consumption from the battery voltage + * measurement. + */ + +void adc_disable_vbat_sensor(void) +{ + ADC_CCR &= ~ADC_CCR_VBATEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Start the calibration procedure + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_calibrate_start(uint32_t adc) +{ + ADC_CR(adc) = ADC_CR_ADCAL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Wait to finish the ADC calibration procedure + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_calibrate_wait_finish(uint32_t adc) +{ + while (ADC_CR(adc) & ADC_CR_ADCAL); +} + +/**@}*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * @defgroup adc_api_wdg ADC Analog watchdog API + * @ingroup adc_file + * + * @brief ADC analog watchdog API definitions. + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Analog watchdog is disabled + * by default. + * + * @warning Comparison is done before data alignment takes place, so the + * thresholds are left-aligned. + * + * Example 1: Enable watchdog checking on all channels + * + * @code + * // in configuration + * adc_enable_analog_watchdog_on_all_channels(ADC1); + * adc_set_watchdog_high_threshold(ADC1, 0xE00); + * adc_set_watchdog_low_threshold(ADC1, 0x200); + * + * // in the main application thread + * if (adc_get_watchdog_flag(ADC1)) { + * // the converted signal is out of AWD ranges + * adc_clear_watchdog_flag(ADC1); + * } + * @endcode + * + * Example 2: Enable watchdog checking on channel 5 + * + * @code + * // in configuration + * adc_enable_analog_watchdog_on_selected_channel(ADC1,5); + * adc_set_watchdog_high_threshold(ADC1, 0xE00); + * adc_set_watchdog_low_threshold(ADC1, 0x200); + * + * // in the main application thread + * if (adc_get_watchdog_flag(ADC1)) { + * // the converted signal is out of AWD ranges + * adc_clear_watchdog_flag(ADC1); + * } + * @endcode + *@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for All Channels + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ + +void adc_enable_analog_watchdog_on_all_channels(uint32_t adc) +{ + ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN; + ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDSGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for a Selected Channel + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] chan Unsigned int8. ADC channel number @ref adc_api_channel + */ + +void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, uint8_t chan) +{ + ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_AWDCH) | + ADC_CFGR1_AWDCH_VAL(chan); + + ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN | ADC_CFGR1_AWDSGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + */ +void adc_disable_analog_watchdog(uint32_t adc) +{ + ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Upper Threshold + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] threshold Unsigned int8. Upper threshold value + */ + +void adc_set_watchdog_high_threshold(uint32_t adc, uint8_t threshold) +{ + ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_HT) | ADC_TR_HT_VAL(threshold); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Lower Threshold + * + * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base) + * @param[in] threshold Unsigned int8. Lower threshold value + */ + +void adc_set_watchdog_low_threshold(uint32_t adc, uint8_t threshold) +{ + ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_LT) | ADC_TR_LT_VAL(threshold); +} + +/**@}*/ + +/*---------------------------------------------------------------------------*/ + +/**@}*/ diff --git a/libopencm3/lib/stm32/f0/comparator.c b/libopencm3/lib/stm32/f0/comparator.c new file mode 100644 index 0000000..51bd0f2 --- /dev/null +++ b/libopencm3/lib/stm32/f0/comparator.c @@ -0,0 +1,64 @@ +/** @defgroup comp_file COMP + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx COMP + * + * @version 1.0.0 + * + * @date 10 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ + +#include + +void comp_enable(uint8_t id) +{ + COMP_CSR(id) |= COMP_CSR_EN; +} + +void comp_disable(uint8_t id) +{ + COMP_CSR(id) &= ~COMP_CSR_EN; +} + +void comp_select_input(uint8_t id, uint32_t input) +{ + COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_INSEL) | input; +} + +void comp_select_output(uint8_t id, uint32_t output) +{ + COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_OUTSEL) | output; +} + +void comp_select_hyst(uint8_t id, uint32_t hyst) +{ + COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_HYST) | hyst; +} + +void comp_select_speed(uint8_t id, uint32_t speed) +{ + COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_SPEED) | speed; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/f0/crc.c b/libopencm3/lib/stm32/f0/crc.c new file mode 100644 index 0000000..2519b22 --- /dev/null +++ b/libopencm3/lib/stm32/f0/crc.c @@ -0,0 +1,31 @@ +/** @defgroup crc_file CRC + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx CRC + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/crs.c b/libopencm3/lib/stm32/f0/crs.c new file mode 100644 index 0000000..db45168 --- /dev/null +++ b/libopencm3/lib/stm32/f0/crs.c @@ -0,0 +1,32 @@ +/** @defgroup crs_file CRS + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Clock Recovery Subsystem + * + * @version 1.0.0 + * + * @date 5 Feb 2014 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + diff --git a/libopencm3/lib/stm32/f0/dac.c b/libopencm3/lib/stm32/f0/dac.c new file mode 100644 index 0000000..55cdd62 --- /dev/null +++ b/libopencm3/lib/stm32/f0/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx DAC + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/dma.c b/libopencm3/lib/stm32/f0/dma.c new file mode 100644 index 0000000..8f158a8 --- /dev/null +++ b/libopencm3/lib/stm32/f0/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx DMA + * + * @version 1.0.0 + * + * @date 10 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/flash.c b/libopencm3/lib/stm32/f0/flash.c new file mode 100644 index 0000000..618405b --- /dev/null +++ b/libopencm3/lib/stm32/f0/flash.c @@ -0,0 +1,157 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F05x FLASH + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2013 + * Frantisek Burian + * + * @date 14 January 2014 + * + * For the STM32F05x, accessing FLASH memory is described in + * section 3 of the STM32F05x Reference Manual. + * + * FLASH memory may be used for data storage as well as code, and may be + * programmatically modified. Note that for firmware upload the STM32F1xx + * provides a built-in bootloader in system memory that can be entered from a + * running program. + * + * FLASH must first be unlocked before programming. In this module a write to + * FLASH is a blocking operation until the end-of-operation flag is asserted. + * + * @note: don't forget to lock it again when all operations are complete. + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Frantisek Burian + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Clear All Status Flags + +Program error, end of operation, write protect error, busy. +*/ + +void flash_clear_status_flags(void) +{ + flash_clear_pgerr_flag(); + flash_clear_eop_flag(); + flash_clear_wrprterr_flag(); + flash_clear_bsy_flag(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read All Status Flags + +The programming error, end of operation, write protect error and busy flags +are returned in the order of appearance in the status register. + +@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect +error, bit 5: end of operation. +*/ + +uint32_t flash_get_status_flags(void) +{ + return (FLASH_SR & (FLASH_SR_PGERR | + FLASH_SR_EOP | + FLASH_SR_WRPRTERR | + FLASH_SR_BSY)); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Half Word to FLASH + +This performs all operations necessary to program a 16 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +Status bit polling is used to detect end of operation. + +@param[in] uint32_t address. Full address of flash half word to be programmed. +@param[in] uint16_t data. +*/ + +void flash_program_half_word(uint32_t address, uint16_t data) +{ + flash_wait_for_last_operation(); + + FLASH_CR |= FLASH_CR_PG; + + MMIO16(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase a Page of FLASH + +This performs all operations necessary to erase a page in FLASH memory. +The page should be checked to ensure that it was properly erased. A page must +first be fully erased before attempting to program it. + +Note that the page sizes differ between devices. See the reference manual or +the FLASH programming manual for details. + +@param[in] uint32_t page_address. Full address of flash page to be erased. +*/ + +void flash_erase_page(uint32_t page_address) +{ + flash_wait_for_last_operation(); + + FLASH_CR |= FLASH_CR_PER; + FLASH_AR = page_address; + FLASH_CR |= FLASH_CR_STRT; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PER; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase All FLASH + +This performs all operations necessary to erase all user pages in the FLASH +memory. The information block is unaffected. +*/ + +void flash_erase_all_pages(void) +{ + flash_wait_for_last_operation(); + + FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */ + FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */ + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */ + +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f0/gpio.c b/libopencm3/lib/stm32/f0/gpio.c new file mode 100644 index 0000000..f60b428 --- /dev/null +++ b/libopencm3/lib/stm32/f0/gpio.c @@ -0,0 +1,31 @@ +/** @defgroup gpio_file GPIO + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx General Purpose I/O + * + * @version 1.0.0 + * + * @date 18 August 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/i2c.c b/libopencm3/lib/stm32/f0/i2c.c new file mode 100644 index 0000000..a39c4be --- /dev/null +++ b/libopencm3/lib/stm32/f0/i2c.c @@ -0,0 +1,32 @@ +/** @defgroup i2c_file I2C + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx I2C + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + diff --git a/libopencm3/lib/stm32/f0/iwdg.c b/libopencm3/lib/stm32/f0/iwdg.c new file mode 100644 index 0000000..b34a652 --- /dev/null +++ b/libopencm3/lib/stm32/f0/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Independent Watchdog Timer + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld b/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/f0/pwr.c b/libopencm3/lib/stm32/f0/pwr.c new file mode 100644 index 0000000..8a3ffd2 --- /dev/null +++ b/libopencm3/lib/stm32/f0/pwr.c @@ -0,0 +1,38 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Power Control + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * This library supports the power control system for the + * STM32F0 series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f0/rcc.c b/libopencm3/lib/stm32/f0/rcc.c new file mode 100644 index 0000000..1f37133 --- /dev/null +++ b/libopencm3/lib/stm32/f0/rcc.c @@ -0,0 +1,665 @@ +/** @defgroup STM32F0xx-rcc-file RCC + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Reset and Clock Control + * + * @version 1.0.0 + * + * @date 29 Jun 2013 + * + * This library supports the Reset and Clock Control System in the STM32F0xx + * series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include + +uint32_t rcc_core_frequency = 8000000; /* 8MHz after reset */ +uint32_t rcc_ppre_frequency = 8000000; /* 8MHz after reset */ + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Clear the Oscillator Ready Interrupt Flag + * + * Clear the interrupt flag that was set when a clock oscillator became ready + * to use. + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_osc_ready_int_clear(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + RCC_CIR |= RCC_CIR_HSI48RDYC; + break; + case HSI14: + RCC_CIR |= RCC_CIR_HSI14RDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable the Oscillator Ready Interrupt + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_osc_ready_int_enable(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + RCC_CIR |= RCC_CIR_HSI48RDYIE; + break; + case HSI14: + RCC_CIR |= RCC_CIR_HSI14RDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable the Oscillator Ready Interrupt + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_osc_ready_int_disable(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + RCC_CIR &= ~RCC_CIR_HSI48RDYC; + break; + case HSI14: + RCC_CIR &= ~RCC_CIR_HSI14RDYC; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYC; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYC; + break; + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYC; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYC; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Read the Oscillator Ready Interrupt Flag + * + * @param[in] osc enum ::osc_t. Oscillator ID + * @returns int. Boolean value for flag set. + */ + +int rcc_osc_ready_int_flag(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + return (RCC_CIR & RCC_CIR_HSI48RDYF) != 0; + break; + case HSI14: + return (RCC_CIR & RCC_CIR_HSI14RDYF) != 0; + break; + case HSI: + return (RCC_CIR & RCC_CIR_HSIRDYF) != 0; + break; + case HSE: + return (RCC_CIR & RCC_CIR_HSERDYF) != 0; + break; + case PLL: + return (RCC_CIR & RCC_CIR_PLLRDYF) != 0; + break; + case LSE: + return (RCC_CIR & RCC_CIR_LSERDYF) != 0; + break; + case LSI: + return (RCC_CIR & RCC_CIR_LSIRDYF) != 0; + break; + } + + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Clear the Clock Security System Interrupt Flag +*/ + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Read the Clock Security System Interrupt Flag + * + * @returns int. Boolean value for flag set. + */ + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Wait for Oscillator Ready. + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_wait_for_osc_ready(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + while ((RCC_CIR & RCC_CIR_HSI48RDYF) != 0); + break; + case HSI14: + while ((RCC_CIR & RCC_CIR_HSI14RDYF) != 0); + break; + case HSI: + while ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case HSE: + while ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case PLL: + while ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case LSE: + while ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + while ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Turn on an Oscillator. + * + * Enable an oscillator and power on. Each oscillator requires an amount of + * time to settle to a usable state. Refer to datasheets for time delay + * information. A status flag is available to indicate when the oscillator + * becomes ready (see @ref rcc_osc_ready_int_flag and @ref + * rcc_wait_for_osc_ready). + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_osc_on(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + RCC_CR2 |= RCC_CR2_HSI48ON; + break; + case HSI14: + RCC_CR2 |= RCC_CR2_HSI14ON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Turn off an Oscillator. + * + * Disable an oscillator and power off. + * + * @note An oscillator cannot be turned off if it is selected as the system + * clock. + * + * @param[in] osc enum ::osc_t. Oscillator ID + */ + +void rcc_osc_off(enum rcc_osc osc) +{ + switch (osc) { + case HSI48: + RCC_CR2 &= ~RCC_CR2_HSI48ON; + break; + case HSI14: + RCC_CR2 &= ~RCC_CR2_HSI14ON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + case PLL: + /* don't do anything */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable the Clock Security System. + */ + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable the Clock Security System. + */ + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable Bypass. + * + * Enable an external clock to bypass the internal clock (high speed and low + * speed clocks only). The external clock must be enabled (see @ref rcc_osc_on) + * and the internal clock must be disabled (see @ref rcc_osc_off) for this to + * have effect. + * + * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect. + */ + +void rcc_osc_bypass_enable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case HSI48: + case HSI14: + case HSI: + case LSI: + case PLL: + /* Do nothing */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable Bypass. + * + * Re-enable the internal clock (high speed and low speed clocks only). The + * internal clock must be disabled (see @ref rcc_osc_off) for this to have + * effect. + * + * + * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect. + */ + +void rcc_osc_bypass_disable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case HSI48: + case HSI14: + case PLL: + case HSI: + case LSI: + /* Do nothing */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the Source for the System Clock. + * + * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE, LSE and PLL have + * effect. + */ + +void rcc_set_sysclk_source(enum rcc_osc clk) +{ + switch (clk) { + case HSI: + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI; + break; + case HSE: + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE; + break; + case PLL: + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL; + break; + case HSI48: + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI48; + break; + case LSI: + case LSE: + case HSI14: + /* do nothing */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the PLL Multiplication Factor. + * + * @note This only has effect when the PLL is disabled. + * + * @param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf + */ + +void rcc_set_pll_multiplication_factor(uint32_t mul) +{ + RCC_CFGR = (RCC_CFGR & RCC_CFGR_PLLMUL) | mul; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the APB Prescale Factor. + * + * @note The APB1 clock frequency must not exceed 36MHz. + * + * @param[in] ppre1 Unsigned int32. APB prescale factor @ref rcc_cfgr_apb1pre + */ + +void rcc_set_ppre(uint32_t ppre) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE) | ppre; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the AHB Prescale Factor. + * + * @param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre + */ + +void rcc_set_hpre(uint32_t hpre) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) | hpre; +} + + +void rcc_set_prediv(uint32_t prediv) +{ + RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv; +} + + +void rcc_set_mco(uint32_t mcosrc) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_MCO) | mcosrc; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Get the System Clock Source. + * + * @returns ::osc_t System clock source: + */ + +enum rcc_osc rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + switch (RCC_CFGR & RCC_CFGR_SWS) { + case RCC_CFGR_SWS_HSI: + return HSI; + case RCC_CFGR_SWS_HSE: + return HSE; + case RCC_CFGR_SWS_PLL: + return PLL; + case RCC_CFGR_SWS_HSI48: + return HSI48; + } + + cm3_assert_not_reached(); +} + +void rcc_clock_setup_in_hsi_out_8mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ); + + rcc_ppre_frequency = 8000000; + rcc_core_frequency = 8000000; +} + +void rcc_clock_setup_in_hsi_out_16mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ); + + /* 8MHz * 4 / 2 = 16MHz */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL4); + + RCC_CFGR &= ~RCC_CFGR_PLLSRC; + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + rcc_set_sysclk_source(PLL); + + rcc_ppre_frequency = 16000000; + rcc_core_frequency = 16000000; +} + + +void rcc_clock_setup_in_hsi_out_24mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ); + + /* 8MHz * 6 / 2 = 24MHz */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL6); + + RCC_CFGR &= ~RCC_CFGR_PLLSRC; + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + rcc_set_sysclk_source(PLL); + + rcc_ppre_frequency = 24000000; + rcc_core_frequency = 24000000; +} + +void rcc_clock_setup_in_hsi_out_32mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ); + + /* 8MHz * 8 / 2 = 32MHz */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL8); + + RCC_CFGR &= ~RCC_CFGR_PLLSRC; + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + rcc_set_sysclk_source(PLL); + + rcc_ppre_frequency = 32000000; + rcc_core_frequency = 32000000; +} + +void rcc_clock_setup_in_hsi_out_40mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ); + + /* 8MHz * 10 / 2 = 40MHz */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL10); + + RCC_CFGR &= ~RCC_CFGR_PLLSRC; + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + rcc_set_sysclk_source(PLL); + + rcc_ppre_frequency = 40000000; + rcc_core_frequency = 40000000; +} + +void rcc_clock_setup_in_hsi_out_48mhz(void) +{ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + rcc_set_sysclk_source(HSI); + + rcc_set_hpre(RCC_CFGR_HPRE_NODIV); + rcc_set_ppre(RCC_CFGR_PPRE_NODIV); + + flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ); + + /* 8MHz * 12 / 2 = 48MHz */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL12); + + RCC_CFGR &= ~RCC_CFGR_PLLSRC; + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + rcc_set_sysclk_source(PLL); + + rcc_ppre_frequency = 48000000; + rcc_core_frequency = 48000000; +} + + +#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5)) +#define _RCC_BIT(i) (1 << ((i) & 0x1f)) + +void rcc_periph_clock_enable(enum rcc_periph_clken periph) +{ + _RCC_REG(periph) |= _RCC_BIT(periph); +} + +void rcc_periph_clock_disable(enum rcc_periph_clken periph) +{ + _RCC_REG(periph) &= ~_RCC_BIT(periph); +} + +void rcc_periph_reset_pulse(enum rcc_periph_rst periph) +{ + _RCC_REG(periph) |= _RCC_BIT(periph); + _RCC_REG(periph) &= ~_RCC_BIT(periph); +} + +void rcc_periph_reset_hold(enum rcc_periph_rst periph) +{ + _RCC_REG(periph) |= _RCC_BIT(periph); +} + +void rcc_periph_reset_release(enum rcc_periph_rst periph) +{ + _RCC_REG(periph) &= ~_RCC_BIT(periph); +} + +#undef _RCC_REG +#undef _RCC_BIT + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f0/rtc.c b/libopencm3/lib/stm32/f0/rtc.c new file mode 100644 index 0000000..6d55cc7 --- /dev/null +++ b/libopencm3/lib/stm32/f0/rtc.c @@ -0,0 +1,31 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx RTC + * + * @version 1.0.0 + * + * @date 10 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/spi.c b/libopencm3/lib/stm32/f0/spi.c new file mode 100644 index 0000000..c341001 --- /dev/null +++ b/libopencm3/lib/stm32/f0/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32F0xx + +@brief libopencm3 STM32F0xx SPI + +@version 1.0.0 + +@date 20 February 2014 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/syscfg.c b/libopencm3/lib/stm32/f0/syscfg.c new file mode 100644 index 0000000..5067d96 --- /dev/null +++ b/libopencm3/lib/stm32/f0/syscfg.c @@ -0,0 +1,31 @@ +/** @defgroup syscfg_file SYSCFG + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx SYSCFG + * + * @version 1.0.0 + * + * @date 10 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f0/timer.c b/libopencm3/lib/stm32/f0/timer.c new file mode 100644 index 0000000..8800683 --- /dev/null +++ b/libopencm3/lib/stm32/f0/timer.c @@ -0,0 +1,34 @@ +/** @defgroup timer_file Timers + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx Timers + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + diff --git a/libopencm3/lib/stm32/f0/usart.c b/libopencm3/lib/stm32/f0/usart.c new file mode 100644 index 0000000..3788926 --- /dev/null +++ b/libopencm3/lib/stm32/f0/usart.c @@ -0,0 +1,429 @@ +/** @defgroup usart_file USART + * + * @ingroup STM32F0xx + * + * @brief libopencm3 STM32F0xx USART + * + * @version 1.0.0 + * + * @date 7 Jul 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Baudrate. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] baud unsigned 32 bit. Baud rate specified in Hz. + */ + +void usart_set_baudrate(uint32_t usart, uint32_t baud) +{ + uint32_t clock = rcc_ppre_frequency; + + if (usart == USART1) { + clock = rcc_ppre_frequency; + /* TODO selective PCLK, SYSCLK, HSI or LSE */ + } + + /* TODO check oversampling 16 */ + USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Word Length. + * + * The word length is set to 8 or 9 bits. Note that the last bit will be a + * parity bit if parity is enabled, in which case the data length will be 7 + * or 8 bits respectively. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] bits unsigned 32 bit. Word length in bits 8 or 9. + */ + +void usart_set_databits(uint32_t usart, uint32_t bits) +{ + if (bits == 8) { + USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */ + } else { + USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */ + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Stop Bit(s). + * + * The stop bits are specified as 0.5, 1, 1.5 or 2. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits. + */ + +void usart_set_stopbits(uint32_t usart, uint32_t stopbits) +{ + USART_CR2(usart) = (USART_CR2(usart) & ~USART_CR2_STOP) | stopbits; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Parity. + * + * The parity bit can be selected as none, even or odd. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity. + */ + +void usart_set_parity(uint32_t usart, uint32_t parity) +{ + USART_CR1(usart) = (USART_CR1(usart) & ~USART_PARITY) | parity; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Rx/Tx Mode. + * + * The mode can be selected as Rx only, Tx only or Rx+Tx. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode. + */ + +void usart_set_mode(uint32_t usart, uint32_t mode) +{ + USART_CR1(usart) = (USART_CR1(usart) & ~USART_MODE) | mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Set Hardware Flow Control. + * + * The flow control bit can be selected as none, RTS, CTS or RTS+CTS. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref + * usart_cr3_flowcontrol. + */ + +void usart_set_flow_control(uint32_t usart, uint32_t flowctrl) +{ + USART_CR3(usart) = (USART_CR3(usart) & ~USART_FLOWCONTROL) | flowctrl; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Enable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_enable(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_UE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Disable. + * + * At the end of the current frame, the USART is disabled to reduce power. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_UE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Send a Data Word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] data unsigned 16 bit. + */ + +void usart_send(uint32_t usart, uint8_t data) +{ + USART_TDR(usart) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Received Data Word. + * + * If parity is enabled the MSB (bit 7 or 8 depending on the word length) is + * the parity bit. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @returns unsigned 16 bit data word. + */ + +uint8_t usart_recv(uint32_t usart) +{ + /* Receive data. */ + return USART_RDR(usart); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Transmit Data Buffer Empty + * + * Blocks until the transmit data buffer becomes empty and is ready to accept + * the next data word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_wait_send_ready(uint32_t usart) +{ + /* Wait until the data has been transferred into the shift register. */ + while ((USART_ISR(usart) & USART_ISR_TXE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Received Data Available + * + * Blocks until the receive data buffer holds a valid received data word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_wait_recv_ready(uint32_t usart) +{ + /* Wait until the data is ready to be received. */ + while ((USART_ISR(usart) & USART_ISR_RXNE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Send Data Word with Blocking + * + * Blocks until the transmit data buffer becomes empty then writes the next + * data word for transmission. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] data unsigned 16 bit. + */ + +void usart_send_blocking(uint32_t usart, uint8_t data) +{ + usart_wait_send_ready(usart); + usart_send(usart, data); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Received Data Word with Blocking. + * + * Wait until a data word has been received then return the word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @returns unsigned 16 bit data word. + */ + +uint8_t usart_recv_blocking(uint32_t usart) +{ + usart_wait_recv_ready(usart); + + return usart_recv(usart); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver DMA Enable. + * + * DMA is available on: + * @li USART1 Rx DMA1 channel 3 or 5. + * @li USART2 Rx DMA1 channel 5. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_enable_rx_dma(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_DMAR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver DMA Disable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable_rx_dma(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_DMAR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter DMA Enable. + * + * DMA is available on: + * @li USART1 Tx DMA1 channel 2 or 4. + * @li USART2 Tx DMA1 channel 4. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_enable_tx_dma(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_DMAT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter DMA Disable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable_tx_dma(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_DMAT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver Interrupt Enable. + +@param[in] usart unsigned 32 bit. USART block register address base @ref +usart_reg_base +*/ + +void usart_enable_rx_interrupt(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_RXNEIE; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief USART Receiver Interrupt Disable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable_rx_interrupt(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_RXNEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter Interrupt Enable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_enable_tx_interrupt(uint32_t usart) +{ + USART_CR1(usart) |= USART_CR1_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Transmitter Interrupt Disable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable_tx_interrupt(uint32_t usart) +{ + USART_CR1(usart) &= ~USART_CR1_TXEIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Error Interrupt Enable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_enable_error_interrupt(uint32_t usart) +{ + USART_CR3(usart) |= USART_CR3_EIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Error Interrupt Disable. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_disable_error_interrupt(uint32_t usart) +{ + USART_CR3(usart) &= ~USART_CR3_EIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Status Flag. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. + * @returns boolean: flag set. + */ + +bool usart_get_flag(uint32_t usart, uint32_t flag) +{ + return ((USART_ISR(usart) & flag) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Return Interrupt Source. + * + * Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was + * set and the interrupt was enabled. If the specified flag is not an interrupt + * flag, the function returns false. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. + * @returns boolean: flag and interrupt enable both set. + */ + +bool usart_get_interrupt_source(uint32_t usart, uint32_t flag) +{ + uint32_t flag_set = (USART_ISR(usart) & flag); + /* IDLE, RXNE, TC, TXE interrupts */ + if ((flag >= USART_ISR_IDLE) && (flag <= USART_ISR_TXE)) { + return ((flag_set & USART_CR1(usart)) != 0); + /* Overrun error */ + } else if (flag == USART_ISR_ORE) { + return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE); + } + + return false; +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/Makefile b/libopencm3/lib/stm32/f1/Makefile new file mode 100644 index 0000000..a4ee7a1 --- /dev/null +++ b/libopencm3/lib/stm32/f1/Makefile @@ -0,0 +1,53 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32f1 +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32F1 +# ARFLAGS = rcsv +ARFLAGS = rcs + +OBJS = adc.o adc_common_v1.o can.o desig.o ethernet.o flash.o gpio.o \ + rcc.o rtc.o timer.o + +OBJS += crc_common_all.o dac_common_all.o dma_common_l1f013.o \ + gpio_common_all.o i2c_common_all.o iwdg_common_all.o \ + pwr_common_all.o spi_common_all.o spi_common_l1f124.o \ + timer_common_all.o usart_common_all.o usart_common_f124.o \ + rcc_common_all.o exti_common_all.o \ + flash_common_f01.o + +OBJS += usb.o usb_control.o usb_standard.o usb_f103.o usb_f107.o \ + usb_fx07_common.o usb_msc.o + +VPATH += ../../usb:../:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/stm32/f1/adc.c b/libopencm3/lib/stm32/f1/adc.c new file mode 100644 index 0000000..e8be6f9 --- /dev/null +++ b/libopencm3/lib/stm32/f1/adc.c @@ -0,0 +1,452 @@ +/** @defgroup adc_file ADC + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx Analog to Digital Converters + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 +Edward Cheeseman +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +@date 18 August 2012 + +This library supports the A/D Converter Control System in the STM32F1xx series +of ARM Cortex Microcontrollers by ST Microelectronics. + +Devices can have up to three A/D converters each with their own set of +registers. However all the A/D converters share a common clock which is +prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum +of 8. + +Each A/D converter has up to 18 channels: +@li On ADC1 the analog channels 16 and 17 are internally connected to the +temperature +sensor and VREFINT, respectively. +@li On ADC2 the analog channels 16 and 17 are internally connected to +VSS. +@li On ADC3 the analog channels 9, 14, 15, 16 and 17 are internally connected +to VSS. + +The conversions can occur as a one-off conversion whereby the process stops +once conversion is complete. The conversions can also be continuous wherein a +new conversion starts immediately the previous conversion has ended. + +Conversion can occur as a single channel conversion or a scan of a group of +channels in either continuous or one-off mode. If more than one channel is +converted in a scan group, DMA must be used to transfer the data as there is +only one result register available. An interrupt can be set to occur at the end +of conversion, which occurs after all channels have been scanned. + +A discontinuous mode allows a subgroup of group of a channels to be converted +in bursts of a given length. + +Injected conversions allow a second group of channels to be converted +separately from the regular group. An interrupt can be set to occur at the end +of conversion, which occurs after all channels have been scanned. + +@section adc_api_ex Basic ADC Handling API. + +Example 1: Simple single channel conversion polled. Enable the peripheral clock +and ADC, reset ADC and set the prescaler divider. Set dual mode to independent +(default). Enable triggering for a software trigger. + +@code + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); + adc_off(ADC1); + rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); + rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); + adc_set_dual_mode(ADC_CR1_DUALMOD_IND); + adc_disable_scan_mode(ADC1); + adc_set_single_conversion_mode(ADC1); + adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC); + adc_set_single_channel(ADC1, ADC_CHANNEL0); + adc_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART); + adc_power_on(ADC1); + adc_reset_calibration(ADC1); + adc_calibration(ADC1); + adc_start_conversion_regular(ADC1); + while (! adc_eoc(ADC1)); + reg16 = adc_read_regular(ADC1); +@endcode + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Edward Cheeseman + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* + * Basic ADC handling API. + * + * Examples: + * rcc_peripheral_enable_clock(&RCC_APB2ENR, ADC1EN); + * rcc_peripheral_disable_clock(&RCC_APB2ENR, ADC1EN); + * rcc_peripheral_reset(&RCC_APB2RSTR, ADC1RST); + * rcc_peripheral_clear_reset(&RCC_APB2RSTR, ADC1RST); + * + * rcc_set_adc_clk(ADC_PRE_PLCK2_DIV2); + * adc_set_dual_mode(ADC1, TODO); + * reg16 = adc_read(ADC1, ADC_CH_0); + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + +If the ADC is in power-down mode then it is powered up. The application needs +to wait a time of about 3 microseconds for stabilization before using the ADC. +If the ADC is already on this function call has no effect. + * NOTE Common with F37x + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_power_on(uint32_t adc) +{ + if (!(ADC_CR2(adc) & ADC_CR2_ADON)) { + ADC_CR2(adc) |= ADC_CR2_ADON; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Start a Conversion Without Trigger + +This initiates a conversion by software without a trigger. The ADC needs to be +powered on before this is called, otherwise this function has no effect. + +Note that this is not available in other STM32F families. To ensure code +compatibility, enable triggering and use a software trigger source @see +adc_start_conversion_regular. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_start_conversion_direct(uint32_t adc) +{ + if (ADC_CR2(adc) & ADC_CR2_ADON) { + ADC_CR2(adc) |= ADC_CR2_ADON; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Dual A/D Mode + +The dual mode uses ADC1 as master and ADC2 in a slave arrangement. This setting +is applied to ADC1 only. Start of conversion when triggered can cause +simultaneous conversion with ADC2, or alternate conversion. Regular and +injected conversions can be configured, each one being separately simultaneous +or alternate. + +Fast interleaved mode starts ADC1 immediately on trigger, and ADC2 seven clock +cycles later. + +Slow interleaved mode starts ADC1 immediately on trigger, and ADC2 fourteen +clock cycles later, followed by ADC1 fourteen cycles later again. This can only +be used on a single channel. + +Alternate trigger mode must occur on an injected channel group, and alternates +between the ADCs on each trigger. + +Note that sampling must not overlap between ADCs on the same channel. + +Dual A/D converter modes possible: + +@li IND: Independent mode. +@li CRSISM: Combined regular simultaneous + injected simultaneous mode. +@li CRSATM: Combined regular simultaneous + alternate trigger mode. +@li CISFIM: Combined injected simultaneous + fast interleaved mode. +@li CISSIM: Combined injected simultaneous + slow interleaved mode. +@li ISM: Injected simultaneous mode only. +@li RSM: Regular simultaneous mode only. +@li FIM: Fast interleaved mode only. +@li SIM: Slow interleaved mode only. +@li ATM: Alternate trigger mode only. + +@param[in] mode Unsigned int32. Dual mode selection from @ref adc_cr1_dualmod +*/ + +void adc_set_dual_mode(uint32_t mode) +{ + ADC1_CR1 |= mode; +} + + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The Temperature Sensor + +This enables both the sensor and the reference voltage measurements on channels +16 and 17. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_enable_temperature_sensor(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_TSVREFE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The Temperature Sensor + +Disabling this will reduce power consumption from the sensor and the reference +voltage measurements. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_disable_temperature_sensor(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_TSVREFE; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Regular Channels + +This enables an external trigger for set of defined regular channels. + +For ADC1 and ADC2 +@li Timer 1 CC1 event +@li Timer 1 CC2 event +@li Timer 1 CC3 event +@li Timer 2 CC2 event +@li Timer 3 TRGO event +@li Timer 4 CC4 event +@li EXTI (TIM8_TRGO is also possible on some devices, see datasheet) +@li Software Start + +For ADC3 +@li Timer 3 CC1 event +@li Timer 2 CC3 event +@li Timer 1 CC3 event +@li Timer 8 CC1 event +@li Timer 8 TRGO event +@li Timer 5 CC1 event +@li Timer 5 CC3 event +@li Software Start + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_regular_12 +for ADC1 and ADC2, or @ref adc_trigger_regular_3 for ADC3. +*/ + +void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger) +{ + uint32_t reg32; + + reg32 = (ADC_CR2(adc) & ~(ADC_CR2_EXTSEL_MASK)); + reg32 |= (trigger); + ADC_CR2(adc) = reg32; + ADC_CR2(adc) |= ADC_CR2_EXTTRIG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Regular Channels + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_disable_external_trigger_regular(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_EXTTRIG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Injected Channels + +This enables an external trigger for set of defined injected channels. + +For ADC1 and ADC2 +@li Timer 1 TRGO event +@li Timer 1 CC4 event +@li Timer 2 TRGO event +@li Timer 2 CC1 event +@li Timer 3 CC4 event +@li Timer 4 TRGO event +@li EXTI (TIM8 CC4 is also possible on some devices, see datasheet) +@li Software Start + +For ADC3 +@li Timer 1 TRGO event +@li Timer 1 CC4 event +@li Timer 4 CC3 event +@li Timer 8 CC2 event +@li Timer 8 CC4 event +@li Timer 5 TRGO event +@li Timer 5 CC4 event +@li Software Start + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +@param[in] trigger Unsigned int8. Trigger identifier @ref +adc_trigger_injected_12 for ADC1 and ADC2, or @ref adc_trigger_injected_3 for +ADC3. +*/ +void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger) +{ + uint32_t reg32; + + reg32 = (ADC_CR2(adc) & ~(ADC_CR2_JEXTSEL_MASK)); /* Clear bits [12:14] + */ + reg32 |= (trigger); + ADC_CR2(adc) = reg32; + ADC_CR2(adc) |= ADC_CR2_JEXTTRIG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Injected Channels + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_disable_external_trigger_injected(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_JEXTTRIG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Initialize Calibration Registers + +This resets the calibration registers. It is not clear if this is required to be +done before every calibration operation. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_reset_calibration(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_RSTCAL; + while (ADC_CR2(adc) & ADC_CR2_RSTCAL); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Calibration + +The calibration data for the ADC is recomputed. The hardware clears the +calibration status flag when calibration is complete. This function does not +return until this happens and the ADC is ready for use. + +The ADC must have been powered down for at least 2 ADC clock cycles, then +powered on. before calibration starts + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_calibration(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_CAL; + while (ADC_CR2(adc) & ADC_CR2_CAL); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + +If the ADC is in power-down mode then it is powered up. The application needs +to wait a time of about 3 microseconds for stabilization before using the ADC. +If the ADC is already on this function call will initiate a conversion. + +@deprecated to be removed in a later release + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +*/ + +void adc_on(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_ADON; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for a Single Channel + +The sampling time can be selected in ADC clock cycles from 1.5 to 239.5. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref +adc_channel. +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg. + * * NOTE Common with f2 and f37x and f4 +*/ + +void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time) +{ + uint32_t reg32; + + if (channel < 10) { + reg32 = ADC_SMPR2(adc); + reg32 &= ~(0x7 << (channel * 3)); + reg32 |= (time << (channel * 3)); + ADC_SMPR2(adc) = reg32; + } else { + reg32 = ADC_SMPR1(adc); + reg32 &= ~(0x7 << ((channel - 10) * 3)); + reg32 |= (time << ((channel - 10) * 3)); + ADC_SMPR1(adc) = reg32; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for All Channels + +The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same +for all channels. + +@param[in] adc Unsigned int32. ADC block register address base @ref +adc_reg_base. +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg. + * * NOTE Common with f2 and f37x and f4 +*/ + +void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time) +{ + uint8_t i; + uint32_t reg32 = 0; + + for (i = 0; i <= 9; i++) { + reg32 |= (time << (i * 3)); + } + ADC_SMPR2(adc) = reg32; + + for (i = 10; i <= 17; i++) { + reg32 |= (time << ((i - 10) * 3)); + } + ADC_SMPR1(adc) = reg32; +} + + +/*---------------------------------------------------------------------------*/ + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/crc.c b/libopencm3/lib/stm32/f1/crc.c new file mode 100644 index 0000000..027052d --- /dev/null +++ b/libopencm3/lib/stm32/f1/crc.c @@ -0,0 +1,31 @@ +/** @defgroup crc_file CRC + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx CRC + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/dac.c b/libopencm3/lib/stm32/f1/dac.c new file mode 100644 index 0000000..fa599bb --- /dev/null +++ b/libopencm3/lib/stm32/f1/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx DAC + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/dma.c b/libopencm3/lib/stm32/f1/dma.c new file mode 100644 index 0000000..7019365 --- /dev/null +++ b/libopencm3/lib/stm32/f1/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx DMA + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/ethernet.c b/libopencm3/lib/stm32/f1/ethernet.c new file mode 100644 index 0000000..8b65780 --- /dev/null +++ b/libopencm3/lib/stm32/f1/ethernet.c @@ -0,0 +1,52 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +void eth_smi_write(uint8_t phy, uint8_t reg, uint16_t data) +{ + /* Set PHY and register addresses for write access. */ + ETH_MACMIIAR &= ~(ETH_MACMIIAR_MR | ETH_MACMIIAR_PA); + ETH_MACMIIAR |= (phy << 11) | (reg << 6) | ETH_MACMIIAR_MW; + + /* Set register value. */ + ETH_MACMIIDR = data; + + /* Begin transaction. */ + ETH_MACMIIAR |= ETH_MACMIIAR_MB; + + /* Wait for not busy. */ + while (ETH_MACMIIAR & ETH_MACMIIAR_MB); +} + +uint16_t eth_smi_read(uint8_t phy, uint8_t reg) +{ + /* Set PHY and register addresses for write access. */ + ETH_MACMIIAR &= ~(ETH_MACMIIAR_MR | ETH_MACMIIAR_PA | ETH_MACMIIAR_MW); + ETH_MACMIIAR |= (phy << 11) | (reg << 6); + + /* Begin transaction. */ + ETH_MACMIIAR |= ETH_MACMIIAR_MB; + + /* Wait for not busy. */ + while (ETH_MACMIIAR & ETH_MACMIIAR_MB); + + /* Set register value. */ + return (uint16_t)(ETH_MACMIIDR); +} diff --git a/libopencm3/lib/stm32/f1/flash.c b/libopencm3/lib/stm32/f1/flash.c new file mode 100644 index 0000000..5712e1c --- /dev/null +++ b/libopencm3/lib/stm32/f1/flash.c @@ -0,0 +1,306 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32F1xx + * + * @brief libopencm3 STM32F1xx FLASH Memory + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * + * @date 14 January 2014 + * + * For the STM32F1xx, accessing FLASH memory is described briefly in + * section 3.3.3 of the STM32F10x Reference Manual. + * For detailed programming information see: + * PM0075 programming manual: STM32F10xxx Flash programming + * August 2010, Doc ID 17863 Rev 1 + * https://github.com/libopencm3/libopencm3-archive/blob/master/st_micro/CD00283419.pdf + * + * FLASH memory may be used for data storage as well as code, and may be + * programmatically modified. Note that for firmware upload the STM32F1xx + * provides a built-in bootloader in system memory that can be entered from a + * running program. + * + * FLASH must first be unlocked before programming. In this module a write to + * FLASH is a blocking operation until the end-of-operation flag is asserted. + * + * @note: don't forget to lock it again when all operations are complete. + * + * For the large memory XL series, with two banks of FLASH, the upper bank is + * accessed with a second set of registers. In principle both banks can be + * written simultaneously, or one read while the other is written. This module + * does not support the simultaneous write feature. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/* Memory Size Register */ +#define MEMORY_SIZE_REG MMIO32(DESIG_FLASH_SIZE_BASE) + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the FLASH Half Cycle Mode + +This mode is used for power saving during read access. It is disabled by default +on reset. + +Note carefully the clock restrictions under which the half cycle mode may be +enabled or disabled. This mode may only be used while the clock is running at +8MHz. See the reference manual for details. +*/ + +void flash_halfcycle_enable(void) +{ + FLASH_ACR |= FLASH_ACR_HLFCYA; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the FLASH Half Cycle Mode + +*/ + +void flash_halfcycle_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_HLFCYA; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Flash Program and Erase Controller, upper Bank + +This enables write access to the upper bank of the Flash memory in XL devices. +It is locked by default on reset. +*/ + +void flash_unlock_upper(void) +{ + if (MEMORY_SIZE_REG > 512) { + + /* Clear the unlock state. */ + FLASH_CR2 |= FLASH_CR_LOCK; + + /* Authorize the FPEC access. */ + FLASH_KEYR2 = FLASH_KEYR_KEY1; + FLASH_KEYR2 = FLASH_KEYR_KEY2; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Flash Program and Erase Controller, upper Bank + +Used to prevent spurious writes to FLASH. +*/ + +void flash_lock_upper(void) +{ + FLASH_CR2 |= FLASH_CR_LOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Error Status Flag, upper Bank + +*/ + +void flash_clear_pgerr_flag_upper(void) +{ + if (MEMORY_SIZE_REG > 512) + FLASH_SR2 |= FLASH_SR_PGERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the End of Operation Status Flag, upper Bank + +*/ + +void flash_clear_eop_flag_upper(void) +{ + if (MEMORY_SIZE_REG > 512) + FLASH_SR2 |= FLASH_SR_EOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Write Protect Error Status Flag, upper Bank + +*/ + +void flash_clear_wrprterr_flag_upper(void) +{ + if (MEMORY_SIZE_REG > 512) + FLASH_SR2 |= FLASH_SR_WRPRTERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Busy Status Flag, upper Bank + +*/ + +void flash_clear_bsy_flag_upper(void) +{ + if (MEMORY_SIZE_REG > 512) + FLASH_SR2 &= ~FLASH_SR_BSY; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear All Status Flags + +Program error, end of operation, write protect error, busy. Both banks cleared. +*/ + +void flash_clear_status_flags(void) +{ + flash_clear_pgerr_flag(); + flash_clear_eop_flag(); + flash_clear_wrprterr_flag(); + flash_clear_bsy_flag(); + if (MEMORY_SIZE_REG > 512) { + flash_clear_pgerr_flag_upper(); + flash_clear_eop_flag_upper(); + flash_clear_wrprterr_flag_upper(); + flash_clear_bsy_flag_upper(); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Read All Status Flags + +The programming error, end of operation, write protect error and busy flags +are returned in the order of appearance in the status register. + +Flags for the upper bank, where appropriate, are combined with those for +the lower bank using bitwise OR, without distinction. + +@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect +error, bit 5: end of operation. +*/ + +uint32_t flash_get_status_flags(void) +{ + uint32_t flags = (FLASH_SR & (FLASH_SR_PGERR | + FLASH_SR_EOP | + FLASH_SR_WRPRTERR | + FLASH_SR_BSY)); + if (MEMORY_SIZE_REG > 512) + flags |= (FLASH_SR2 & (FLASH_SR_PGERR | + FLASH_SR_EOP | + FLASH_SR_WRPRTERR | + FLASH_SR_BSY)); + return flags; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Half Word to FLASH + +This performs all operations necessary to program a 16 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +Status bit polling is used to detect end of operation. + +@param[in] uint32_t address. Full address of flash half word to be programmed. +@param[in] uint16_t data. +*/ + +void flash_program_half_word(uint32_t address, uint16_t data) +{ + flash_wait_for_last_operation(); + + if ((MEMORY_SIZE_REG > 512) && (address >= FLASH_BASE+0x00080000)) + FLASH_CR2 |= FLASH_CR_PG; + else FLASH_CR |= FLASH_CR_PG; + + MMIO16(address) = data; + + flash_wait_for_last_operation(); + + if ((MEMORY_SIZE_REG > 512) && (address >= FLASH_BASE+0x00080000)) + FLASH_CR2 &= ~FLASH_CR_PG; + else FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase a Page of FLASH + +This performs all operations necessary to erase a page in FLASH memory. +The page should be checked to ensure that it was properly erased. A page must +first be fully erased before attempting to program it. + +Note that the page sizes differ between devices. See the reference manual or +the FLASH programming manual for details. + +@param[in] uint32_t page_address. Full address of flash page to be erased. +*/ + +void flash_erase_page(uint32_t page_address) +{ + flash_wait_for_last_operation(); + + if ((MEMORY_SIZE_REG > 512) && (page_address >= FLASH_BASE+0x00080000)) { + FLASH_CR2 |= FLASH_CR_PER; + FLASH_AR2 = page_address; + FLASH_CR2 |= FLASH_CR_STRT; + } else { + FLASH_CR |= FLASH_CR_PER; + FLASH_AR = page_address; + FLASH_CR |= FLASH_CR_STRT; + } + + flash_wait_for_last_operation(); + + if ((MEMORY_SIZE_REG > 512) && (page_address >= FLASH_BASE+0x00080000)) + FLASH_CR2 &= ~FLASH_CR_PER; + else + FLASH_CR &= ~FLASH_CR_PER; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase All FLASH + +This performs all operations necessary to erase all user pages in the FLASH +memory. The information block is unaffected. +*/ + +void flash_erase_all_pages(void) +{ + flash_wait_for_last_operation(); + + FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */ + FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */ + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */ + +/* Repeat for bank 2 */ + FLASH_CR2 |= FLASH_CR_MER; + FLASH_CR2 |= FLASH_CR_STRT; + + flash_wait_for_last_operation(); + FLASH_CR2 &= ~FLASH_CR_MER; +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/gpio.c b/libopencm3/lib/stm32/f1/gpio.c new file mode 100644 index 0000000..76cbd5b --- /dev/null +++ b/libopencm3/lib/stm32/f1/gpio.c @@ -0,0 +1,194 @@ +/** @defgroup gpio_file GPIO + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx General Purpose I/O + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 +Uwe Hermann +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +@date 18 August 2012 + +Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO +functionality with a number of alternate functions and must be configured to +the alternate function mode if these are to be accessed. A feature is available +to remap alternative functions to a limited set of alternative pins in the +event of a clash of requirements. + +The data registers associated with each port for input and output are 32 bit +with the upper 16 bits unused. The output buffer must be written as a 32 bit +word, but individual bits may be set or reset separately in atomic operations +to avoid race conditions during interrupts. Bits may also be individually +locked to prevent accidental configuration changes. Once locked the +configuration cannot be changed until after the next reset. + +Each port bit can be configured as analog or digital input, the latter can be +floating or pulled up or down. As outputs they can be configured as either +push-pull or open drain, digital I/O or alternate function, and with maximum +output speeds of 2MHz, 10MHz, or 50MHz. + +On reset all ports are configured as digital floating input. + +@section gpio_api_ex Basic GPIO Handling API. + +Example 1: Push-pull digital output actions on ports C2 and C9 + +@code + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO2 | GPIO9); + gpio_set(GPIOC, GPIO2 | GPIO9); + gpio_clear(GPIOC, GPIO2); + gpio_toggle(GPIOC, GPIO2 | GPIO9); + gpio_port_write(GPIOC, 0x204); +@endcode + +Example 1: Digital input on port C12 + +@code + gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT, GPIO12); + reg16 = gpio_port_read(GPIOC); +@endcode + +LGPL License Terms @ref lgpl_license +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief Set GPIO Pin Mode + +Sets the mode (input/output) and configuration (analog/digitial and +open drain/push pull), for a set of GPIO pins on a given GPIO port. + +@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id +@param[in] mode Unsigned int8. Pin mode @ref gpio_mode +@param[in] cnf Unsigned int8. Pin configuration @ref gpio_cnf +@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id + If multiple pins are to be set, use logical OR '|' to separate + them. +*/ + +void gpio_set_mode(uint32_t gpioport, uint8_t mode, uint8_t cnf, uint16_t gpios) +{ + uint16_t i, offset = 0; + uint32_t crl = 0, crh = 0, tmp32 = 0; + + /* + * We want to set the config only for the pins mentioned in gpios, + * but keeping the others, so read out the actual config first. + */ + crl = GPIO_CRL(gpioport); + crh = GPIO_CRH(gpioport); + + /* Iterate over all bits, use i as the bitnumber. */ + for (i = 0; i < 16; i++) { + /* Only set the config if the bit is set in gpios. */ + if (!((1 << i) & gpios)) { + continue; + } + + /* Calculate bit offset. */ + offset = (i < 8) ? (i * 4) : ((i - 8) * 4); + + /* Use tmp32 to either modify crl or crh. */ + tmp32 = (i < 8) ? crl : crh; + + /* Modify bits are needed. */ + tmp32 &= ~(0xf << offset); /* Clear the bits first. */ + tmp32 |= (mode << offset) | (cnf << (offset + 2)); + + /* Write tmp32 into crl or crh, leave the other unchanged. */ + crl = (i < 8) ? tmp32 : crl; + crh = (i >= 8) ? tmp32 : crh; + } + + GPIO_CRL(gpioport) = crl; + GPIO_CRH(gpioport) = crh; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Map the EVENTOUT signal + +Enable the EVENTOUT signal and select the port and pin to be used. + +@param[in] evoutport Unsigned int8. Port for EVENTOUT signal @ref afio_evcr_port +@param[in] evoutpin Unsigned int8. Pin for EVENTOUT signal @ref afio_evcr_pin +*/ +void gpio_set_eventout(uint8_t evoutport, uint8_t evoutpin) +{ + AFIO_EVCR = AFIO_EVCR_EVOE | evoutport | evoutpin; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Map Alternate Function Port Bits (Main Set) + +A number of alternate function ports can be remapped to defined alternative +port bits to avoid clashes in cases where multiple alternate functions are +present. Refer to the datasheets for the particular mapping desired. This +provides the main set of remap functionality. See @ref gpio_secondary_remap for +a number of lesser used remaps. + +The AFIO remapping feature is used only with the STM32F10x series. + +@note The Serial Wire JTAG disable controls allow certain GPIO ports to become +available in place of some of the SWJ signals. Full SWJ capability is obtained +by setting this to zero. The value of this must be specified for every call to +this function as its current value cannot be ascertained from the hardware. + +@param[in] swjdisable Unsigned int8. Disable parts of the SWJ capability @ref +afio_swj_disable. +@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref +afio_remap, @ref afio_remap_can1, @ref afio_remap_tim3, @ref afio_remap_tim2, +@ref afio_remap_tim1, @ref afio_remap_usart3. For connectivity line devices +only @ref afio_remap_cld are also available. +*/ +void gpio_primary_remap(uint32_t swjdisable, uint32_t maps) +{ + AFIO_MAPR |= (swjdisable & AFIO_MAPR_SWJ_MASK) | (maps & 0x1FFFFF); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Map Alternate Function Port Bits (Secondary Set) + +A number of alternate function ports can be remapped to defined alternative +port bits to avoid clashes in cases where multiple alternate functions are +present. Refer to the datasheets for the particular mapping desired. This +provides the second smaller and less used set of remap functionality. See @ref +gpio_primary_remap for the main set of remaps. + +The AFIO remapping feature is used only with the STM32F10x series. + +@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref +afio_remap2 +*/ +void gpio_secondary_remap(uint32_t maps) +{ + AFIO_MAPR2 |= maps; +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/i2c.c b/libopencm3/lib/stm32/f1/i2c.c new file mode 100644 index 0000000..d961736 --- /dev/null +++ b/libopencm3/lib/stm32/f1/i2c.c @@ -0,0 +1,31 @@ +/** @defgroup i2c_file I2C + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx I2C + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/iwdg.c b/libopencm3/lib/stm32/f1/iwdg.c new file mode 100644 index 0000000..2d9bc3c --- /dev/null +++ b/libopencm3/lib/stm32/f1/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx Independent Watchdog Timer + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld b/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/f1/pwr.c b/libopencm3/lib/stm32/f1/pwr.c new file mode 100644 index 0000000..167f920 --- /dev/null +++ b/libopencm3/lib/stm32/f1/pwr.c @@ -0,0 +1,43 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32F1xx + * + * @brief libopencm3 STM32F1xx Power Control + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2012 + * Ken Sarkies + * + * @date 18 August 2012 + * + * This library supports the power control system for the + * STM32F1 series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/rcc.c b/libopencm3/lib/stm32/f1/rcc.c new file mode 100644 index 0000000..c69ba15 --- /dev/null +++ b/libopencm3/lib/stm32/f1/rcc.c @@ -0,0 +1,1106 @@ +/** @defgroup STM32F1xx-rcc-file RCC + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx Reset and Clock Control + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2009 +Federico Ruiz-Ugalde \ +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann +@author @htmlonly © @endhtmlonly 2010 Thomas Otto + +@date 18 August 2012 + +This library supports the Reset and Clock Control System in the STM32F1xx +series of ARM Cortex Microcontrollers by ST Microelectronics. + +@note Full support for connection line devices is not yet provided. + +Clock settings and resets for many peripherals are given here rather than in +the corresponding peripheral library. + +The library also provides a number of common configurations for the processor +system clock. Not all possible configurations are included. + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include + +/** Default ppre1 peripheral clock frequency after reset. */ +uint32_t rcc_ppre1_frequency = 8000000; +/** Default ppre2 peripheral clock frequency after reset. */ +uint32_t rcc_ppre2_frequency = 8000000; + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Clear the Oscillator Ready Interrupt Flag + +Clear the interrupt flag that was set when a clock oscillator became ready to +use. + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_osc_ready_int_clear(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case PLL2: + RCC_CIR |= RCC_CIR_PLL2RDYC; + break; + case PLL3: + RCC_CIR |= RCC_CIR_PLL3RDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable the Oscillator Ready Interrupt + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_osc_ready_int_enable(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case PLL2: + RCC_CIR |= RCC_CIR_PLL2RDYIE; + break; + case PLL3: + RCC_CIR |= RCC_CIR_PLL3RDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable the Oscillator Ready Interrupt + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_osc_ready_int_disable(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case PLL2: + RCC_CIR &= ~RCC_CIR_PLL2RDYIE; + break; + case PLL3: + RCC_CIR &= ~RCC_CIR_PLL3RDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Read the Oscillator Ready Interrupt Flag + +@param[in] osc enum ::osc_t. Oscillator ID +@returns int. Boolean value for flag set. +*/ + +int rcc_osc_ready_int_flag(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case PLL2: + return ((RCC_CIR & RCC_CIR_PLL2RDYF) != 0); + break; + case PLL3: + return ((RCC_CIR & RCC_CIR_PLL3RDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } + + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Clear the Clock Security System Interrupt Flag + +*/ + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Read the Clock Security System Interrupt Flag + +@returns int. Boolean value for flag set. +*/ + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Wait for Oscillator Ready. + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_wait_for_osc_ready(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case PLL2: + while ((RCC_CR & RCC_CR_PLL2RDY) == 0); + break; + case PLL3: + while ((RCC_CR & RCC_CR_PLL3RDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Turn on an Oscillator. + +Enable an oscillator and power on. Each oscillator requires an amount of time +to settle to a usable state. Refer to datasheets for time delay information. A +status flag is available to indicate when the oscillator becomes ready (see +@ref rcc_osc_ready_int_flag and @ref rcc_wait_for_osc_ready). + +@note The LSE clock is in the backup domain and cannot be enabled until the +backup domain write protection has been removed (see @ref +pwr_disable_backup_domain_write_protect). + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_osc_on(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case PLL2: + RCC_CR |= RCC_CR_PLL2ON; + break; + case PLL3: + RCC_CR |= RCC_CR_PLL3ON; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Turn off an Oscillator. + +Disable an oscillator and power off. + +@note An oscillator cannot be turned off if it is selected as the system clock. +@note The LSE clock is in the backup domain and cannot be disabled until the +backup domain write protection has been removed (see +@ref pwr_disable_backup_domain_write_protect) or the backup domain has been +(see reset @ref rcc_backupdomain_reset). + +@param[in] osc enum ::osc_t. Oscillator ID +*/ + +void rcc_osc_off(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case PLL2: + RCC_CR &= ~RCC_CR_PLL2ON; + break; + case PLL3: + RCC_CR &= ~RCC_CR_PLL3ON; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable the Clock Security System. + +*/ + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable the Clock Security System. + +*/ + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Enable Bypass. + +Enable an external clock to bypass the internal clock (high speed and low speed +clocks only). The external clock must be enabled (see @ref rcc_osc_on) and the +internal clock must be disabled (see @ref rcc_osc_off) for this to have effect. + +@note The LSE clock is in the backup domain and cannot be bypassed until the +backup domain write protection has been removed (see @ref +pwr_disable_backup_domain_write_protect). + +@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect. +*/ + +void rcc_osc_bypass_enable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case PLL: + case PLL2: + case PLL3: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Disable Bypass. + +Re-enable the internal clock (high speed and low speed clocks only). The +internal clock must be disabled (see @ref rcc_osc_off) for this to have effect. + +@note The LSE clock is in the backup domain and cannot have bypass removed +until the backup domain write protection has been removed (see @ref +pwr_disable_backup_domain_write_protect) or the backup domain has been reset +(see @ref rcc_backupdomain_reset). + +@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect. +*/ + +void rcc_osc_bypass_disable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case PLL: + case PLL2: + case PLL3: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the Source for the System Clock. + +@param[in] clk Unsigned int32. System Clock Selection @ref rcc_cfgr_scs +*/ + +void rcc_set_sysclk_source(uint32_t clk) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | + (clk << RCC_CFGR_SW_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the PLL Multiplication Factor. + +@note This only has effect when the PLL is disabled. + +@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf +*/ + +void rcc_set_pll_multiplication_factor(uint32_t mul) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLMUL) | + (mul << RCC_CFGR_PLLMUL_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the PLL2 Multiplication Factor. + +@note This only has effect when the PLL is disabled. + +@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf +*/ + +void rcc_set_pll2_multiplication_factor(uint32_t mul) +{ + RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PLL2MUL) | + (mul << RCC_CFGR2_PLL2MUL_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the PLL3 Multiplication Factor. + +@note This only has effect when the PLL is disabled. + +@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf +*/ + +void rcc_set_pll3_multiplication_factor(uint32_t mul) +{ + RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PLL3MUL) | + (mul << RCC_CFGR2_PLL3MUL_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the PLL Clock Source. + +@note This only has effect when the PLL is disabled. + +@param[in] pllsrc Unsigned int32. PLL clock source @ref rcc_cfgr_pcs +*/ + +void rcc_set_pll_source(uint32_t pllsrc) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLSRC) | + (pllsrc << 16); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the HSE Frequency Divider used as PLL Clock Source. + +@note This only has effect when the PLL is disabled. + +@param[in] pllxtpre Unsigned int32. HSE division factor @ref rcc_cfgr_hsepre +*/ + +void rcc_set_pllxtpre(uint32_t pllxtpre) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLXTPRE) | + (pllxtpre << 17); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Setup the A/D Clock + +The ADC's have a common clock prescale setting. + +@param[in] adcpre uint32_t. Prescale divider taken from @ref rcc_cfgr_adcpre +*/ + +void rcc_set_adcpre(uint32_t adcpre) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_ADCPRE) | + (adcpre << RCC_CFGR_ADCPRE_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the APB2 Prescale Factor. + +@param[in] ppre2 Unsigned int32. APB2 prescale factor @ref rcc_cfgr_apb2pre +*/ + +void rcc_set_ppre2(uint32_t ppre2) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE2) | + (ppre2 << RCC_CFGR_PPRE2_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the APB1 Prescale Factor. + +@note The APB1 clock frequency must not exceed 36MHz. + +@param[in] ppre1 Unsigned int32. APB1 prescale factor @ref rcc_cfgr_apb1pre +*/ + +void rcc_set_ppre1(uint32_t ppre1) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE1) | + (ppre1 << RCC_CFGR_PPRE1_SHIFT); + +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the AHB Prescale Factor. + +@param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre +*/ + +void rcc_set_hpre(uint32_t hpre) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) | + (hpre << RCC_CFGR_HPRE_SHIFT); + +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set the USB Prescale Factor. + +The prescale factor can be set to 1 (no prescale) for use when the PLL clock is +48MHz, or 1.5 to generate the 48MHz USB clock from a 64MHz PLL clock. + +@note This bit cannot be reset while the USB clock is enabled. + +@param[in] usbpre Unsigned int32. USB prescale factor @ref rcc_cfgr_usbpre +*/ + +void rcc_set_usbpre(uint32_t usbpre) +{ + if (usbpre) + RCC_CFGR |= RCC_CFGR_USBPRE; + else + RCC_CFGR &= ~RCC_CFGR_USBPRE; +} + +void rcc_set_prediv1(uint32_t prediv) +{ + RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV1) | + (prediv << RCC_CFGR2_PREDIV1_SHIFT); +} + +void rcc_set_prediv2(uint32_t prediv) +{ + RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV2) | + (prediv << RCC_CFGR2_PREDIV2_SHIFT); +} + +void rcc_set_prediv1_source(uint32_t rccsrc) +{ + if (rccsrc) + RCC_CFGR2 |= RCC_CFGR2_PREDIV1SRC; + else + RCC_CFGR2 &= ~RCC_CFGR2_PREDIV1SRC; +} + +void rcc_set_mco(uint32_t mcosrc) +{ + RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_MCO) | + (mcosrc << RCC_CFGR_MCO_SHIFT); + +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Get the System Clock Source. + +@returns Unsigned int32. System clock source: +@li 00 indicates HSE +@li 01 indicates LSE +@li 02 indicates PLL +*/ + +uint32_t rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return (RCC_CFGR & RCC_CFGR_SWS) >> RCC_CFGR_SWS_SHIFT; +} + +/*---------------------------------------------------------------------------*/ +/* + * These functions are setting up the whole clock system for the most common + * input clock and output clock configurations. + */ +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 64MHz from HSI + +*/ + +void rcc_clock_setup_in_hsi_out_64mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 64MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /* Set. 8MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 32MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 64MHz Max. 72MHz */ + + /* + * Sysclk is running with 64MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_2WS); + + /* + * Set the PLL multiplication factor to 16. + * 8MHz (internal) * 16 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 64MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL16); + + /* Select HSI/2 as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 32000000; + rcc_ppre2_frequency = 64000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 48MHz from HSI + +*/ + +void rcc_clock_setup_in_hsi_out_48mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /*Set.48MHz Max.72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /*Set. 6MHz Max.14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /*Set.24MHz Max.36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /*Set.48MHz Max.72MHz */ + rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_CLK_NODIV); /*Set.48MHz Max.48MHz */ + + /* + * Sysclk runs with 48MHz -> 1 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_1WS); + + /* + * Set the PLL multiplication factor to 12. + * 8MHz (internal) * 12 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 48MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL12); + + /* Select HSI/2 as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 24000000; + rcc_ppre2_frequency = 48000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 24MHz from HSI + +*/ + +void rcc_clock_setup_in_hsi_out_24mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 24MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 12MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */ + + /* + * Sysclk is (will be) running with 24MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_0WS); + + /* + * Set the PLL multiplication factor to 6. + * 8MHz (internal) * 6 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 24MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6); + + /* Select HSI/2 as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 24000000; + rcc_ppre2_frequency = 24000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 24MHz from HSE at 8MHz + +*/ + +void rcc_clock_setup_in_hse_8mhz_out_24mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* Enable external high-speed oscillator 8MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 72MHz */ + + /* + * Sysclk runs with 24MHz -> 0 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_0WS); + + /* + * Set the PLL multiplication factor to 3. + * 8MHz (external) * 3 (multiplier) = 24MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL3); + + /* Select HSE as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK); + + /* + * External frequency undivided before entering PLL + * (only valid/needed for HSE). + */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 24000000; + rcc_ppre2_frequency = 24000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 72MHz from HSE at 8MHz + +*/ + +void rcc_clock_setup_in_hse_8mhz_out_72mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* Enable external high-speed oscillator 8MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /* Set. 9MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + + /* + * Sysclk runs with 72MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_2WS); + + /* + * Set the PLL multiplication factor to 9. + * 8MHz (external) * 9 (multiplier) = 72MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9); + + /* Select HSE as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK); + + /* + * External frequency undivided before entering PLL + * (only valid/needed for HSE). + */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 36000000; + rcc_ppre2_frequency = 72000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 24MHz from HSE at 12MHz + +*/ + +void rcc_clock_setup_in_hse_12mhz_out_72mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* Enable external high-speed oscillator 16MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + + /* + * Sysclk runs with 72MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_2WS); + + /* + * Set the PLL multiplication factor to 9. + * 12MHz (external) * 6 (multiplier) / 1 (PLLXTPRE_HSE_CLK) = 72MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6); + + /* Select HSI as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK); + + /* + * Divide external frequency by 2 before entering PLL + * (only valid/needed for HSE). + */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 36000000; + rcc_ppre2_frequency = 72000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 24MHz from HSE at 16MHz + +*/ + +void rcc_clock_setup_in_hse_16mhz_out_72mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* Enable external high-speed oscillator 16MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + + /* + * Sysclk runs with 72MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_2WS); + + /* + * Set the PLL multiplication factor to 9. + * 16MHz (external) * 9 (multiplier) / 2 (PLLXTPRE_HSE_CLK_DIV2) = 72MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9); + + /* Select HSI as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK); + + /* + * Divide external frequency by 2 before entering PLL + * (only valid/needed for HSE). + */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK_DIV2); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 36000000; + rcc_ppre2_frequency = 72000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock PLL at 72MHz from HSE at 25MHz + +*/ + +void rcc_clock_setup_in_hse_25mhz_out_72mhz(void) +{ + /* Enable external high-speed oscillator 25MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Sysclk runs with 72MHz -> 2 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_2WS); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */ + + /* Set pll2 prediv and multiplier */ + rcc_set_prediv2(RCC_CFGR2_PREDIV2_DIV5); + rcc_set_pll2_multiplication_factor(RCC_CFGR2_PLL2MUL_PLL2_CLK_MUL8); + + /* Enable PLL2 oscillator and wait for it to stabilize */ + rcc_osc_on(PLL2); + rcc_wait_for_osc_ready(PLL2); + + /* Set pll1 prediv/multiplier, prediv1 src, and usb predivider */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK); + rcc_set_prediv1_source(RCC_CFGR2_PREDIV1SRC_PLL2_CLK); + rcc_set_prediv1(RCC_CFGR2_PREDIV_DIV5); + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9); + rcc_set_pll_source(RCC_CFGR_PLLSRC_PREDIV1_CLK); + rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3); + + /* enable PLL1 and wait for it to stabilize */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 36000000; + rcc_ppre2_frequency = 72000000; +} + +/*---------------------------------------------------------------------------*/ +/** @brief RCC Reset the backup domain + +The backup domain register is reset to disable all controls. +*/ + +void rcc_backupdomain_reset(void) +{ + /* Set the backup domain software reset. */ + RCC_BDCR |= RCC_BDCR_BDRST; + + /* Clear the backup domain software reset. */ + RCC_BDCR &= ~RCC_BDCR_BDRST; +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/rtc.c b/libopencm3/lib/stm32/f1/rtc.c new file mode 100644 index 0000000..b2d7b83 --- /dev/null +++ b/libopencm3/lib/stm32/f1/rtc.c @@ -0,0 +1,305 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32F1xx + * + * @brief libopencm3 STM32F1xx RTC + * + * @author @htmlonly © @endhtmlonly 2010 Uwe Hermann + * @author @htmlonly © @endhtmlonly 2010 Lord James + * + * @version 1.0.0 + * + * @date 4 March 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Uwe Hermann + * Copyright (C) 2010 Lord James + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ + + +#include +#include +#include + +void rtc_awake_from_off(enum rcc_osc clock_source) +{ + uint32_t reg32; + + /* Enable power and backup interface clocks. */ + RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); + + /* Enable access to the backup registers and the RTC. */ + PWR_CR |= PWR_CR_DBP; + + /* + * Reset the backup domain, clears everything RTC related. + * If not wanted use the rtc_awake_from_standby() function. + */ + rcc_backupdomain_reset(); + + switch (clock_source) { + case LSE: + /* Turn the LSE on and wait while it stabilises. */ + RCC_BDCR |= RCC_BDCR_LSEON; + while ((reg32 = (RCC_BDCR & RCC_BDCR_LSERDY)) == 0); + + /* Choose LSE as the RTC clock source. */ + RCC_BDCR &= ~((1 << 8) | (1 << 9)); + RCC_BDCR |= (1 << 8); + break; + case LSI: + /* Turn the LSI on and wait while it stabilises. */ + RCC_CSR |= RCC_CSR_LSION; + while ((reg32 = (RCC_CSR & RCC_CSR_LSIRDY)) == 0); + + /* Choose LSI as the RTC clock source. */ + RCC_BDCR &= ~((1 << 8) | (1 << 9)); + RCC_BDCR |= (1 << 9); + break; + case HSE: + /* Turn the HSE on and wait while it stabilises. */ + RCC_CR |= RCC_CR_HSEON; + while ((reg32 = (RCC_CR & RCC_CR_HSERDY)) == 0); + + /* Choose HSE as the RTC clock source. */ + RCC_BDCR &= ~((1 << 8) | (1 << 9)); + RCC_BDCR |= (1 << 9) | (1 << 8); + break; + case PLL: + case PLL2: + case PLL3: + case HSI: + /* Unusable clock source, here to prevent warnings. */ + /* Turn off clock sources to RTC. */ + RCC_BDCR &= ~((1 << 8) | (1 << 9)); + break; + } + + /* Enable the RTC. */ + RCC_BDCR |= RCC_BDCR_RTCEN; + + /* Wait for the RSF bit in RTC_CRL to be set by hardware. */ + RTC_CRL &= ~RTC_CRL_RSF; + while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0); + + /* Wait for the last write operation to finish. */ + /* TODO: Necessary? */ + while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0); +} + +void rtc_enter_config_mode(void) +{ + uint32_t reg32; + + /* Wait until the RTOFF bit is 1 (no RTC register writes ongoing). */ + while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0); + + /* Enter configuration mode. */ + RTC_CRL |= RTC_CRL_CNF; +} + +void rtc_exit_config_mode(void) +{ + uint32_t reg32; + + /* Exit configuration mode. */ + RTC_CRL &= ~RTC_CRL_CNF; + + /* Wait until the RTOFF bit is 1 (our RTC register write finished). */ + while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0); +} + +void rtc_set_alarm_time(uint32_t alarm_time) +{ + rtc_enter_config_mode(); + RTC_ALRL = (alarm_time & 0x0000ffff); + RTC_ALRH = (alarm_time & 0xffff0000) >> 16; + rtc_exit_config_mode(); +} + +void rtc_enable_alarm(void) +{ + rtc_enter_config_mode(); + RTC_CRH |= RTC_CRH_ALRIE; + rtc_exit_config_mode(); +} + +void rtc_disable_alarm(void) +{ + rtc_enter_config_mode(); + RTC_CRH &= ~RTC_CRH_ALRIE; + rtc_exit_config_mode(); +} + +void rtc_set_prescale_val(uint32_t prescale_val) +{ + rtc_enter_config_mode(); + RTC_PRLL = prescale_val & 0x0000ffff; /* PRL[15:0] */ + RTC_PRLH = (prescale_val & 0x000f0000) >> 16; /* PRL[19:16] */ + rtc_exit_config_mode(); +} + +uint32_t rtc_get_counter_val(void) +{ + return (RTC_CNTH << 16) | RTC_CNTL; +} + +uint32_t rtc_get_prescale_div_val(void) +{ + return (RTC_DIVH << 16) | RTC_DIVL; +} + +uint32_t rtc_get_alarm_val(void) +{ + return (RTC_ALRH << 16) | RTC_ALRL; +} + +void rtc_set_counter_val(uint32_t counter_val) +{ + rtc_enter_config_mode(); + RTC_CNTH = (counter_val & 0xffff0000) >> 16; /* CNT[31:16] */ + RTC_CNTL = counter_val & 0x0000ffff; /* CNT[15:0] */ + rtc_exit_config_mode(); +} + +void rtc_interrupt_enable(rtcflag_t flag_val) +{ + rtc_enter_config_mode(); + + /* Set the correct interrupt enable. */ + switch (flag_val) { + case RTC_SEC: + RTC_CRH |= RTC_CRH_SECIE; + break; + case RTC_ALR: + RTC_CRH |= RTC_CRH_ALRIE; + break; + case RTC_OW: + RTC_CRH |= RTC_CRH_OWIE; + break; + } + + rtc_exit_config_mode(); +} + +void rtc_interrupt_disable(rtcflag_t flag_val) +{ + rtc_enter_config_mode(); + + /* Disable the correct interrupt enable. */ + switch (flag_val) { + case RTC_SEC: + RTC_CRH &= ~RTC_CRH_SECIE; + break; + case RTC_ALR: + RTC_CRH &= ~RTC_CRH_ALRIE; + break; + case RTC_OW: + RTC_CRH &= ~RTC_CRH_OWIE; + break; + } + + rtc_exit_config_mode(); +} + +void rtc_clear_flag(rtcflag_t flag_val) +{ + /* Configuration mode not needed. */ + + /* Clear the correct flag. */ + switch (flag_val) { + case RTC_SEC: + RTC_CRL &= ~RTC_CRL_SECF; + break; + case RTC_ALR: + RTC_CRL &= ~RTC_CRL_ALRF; + break; + case RTC_OW: + RTC_CRL &= ~RTC_CRL_OWF; + break; + } +} + +uint32_t rtc_check_flag(rtcflag_t flag_val) +{ + uint32_t reg32; + + /* Read correct flag. */ + switch (flag_val) { + case RTC_SEC: + reg32 = RTC_CRL & RTC_CRL_SECF; + break; + case RTC_ALR: + reg32 = RTC_CRL & RTC_CRL_ALRF; + break; + case RTC_OW: + reg32 = RTC_CRL & RTC_CRL_OWF; + break; + default: + reg32 = 0; + break; + } + + return reg32; +} + +void rtc_awake_from_standby(void) +{ + uint32_t reg32; + + /* Enable power and backup interface clocks. */ + RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); + + /* Enable access to the backup registers and the RTC. */ + PWR_CR |= PWR_CR_DBP; + + /* Wait for the RSF bit in RTC_CRL to be set by hardware. */ + RTC_CRL &= ~RTC_CRL_RSF; + while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0); + + /* Wait for the last write operation to finish. */ + /* TODO: Necessary? */ + while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0); +} + +void rtc_auto_awake(enum rcc_osc clock_source, uint32_t prescale_val) +{ + uint32_t reg32; + + /* Enable power and backup interface clocks. */ + RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); + + /* Enable access to the backup registers and the RTC. */ + /* TODO: Not sure if this is necessary to just read the flag. */ + PWR_CR |= PWR_CR_DBP; + + reg32 = RCC_BDCR & RCC_BDCR_RTCEN; + + if (reg32 != 0) { + rtc_awake_from_standby(); + } else { + rtc_awake_from_off(clock_source); + rtc_set_prescale_val(prescale_val); + } +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/f1/spi.c b/libopencm3/lib/stm32/f1/spi.c new file mode 100644 index 0000000..757f2ae --- /dev/null +++ b/libopencm3/lib/stm32/f1/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx SPI + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f1/stm32f100x4.ld b/libopencm3/lib/stm32/f1/stm32f100x4.ld new file mode 100644 index 0000000..4c86aee --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100x4.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100x6.ld b/libopencm3/lib/stm32/f1/stm32f100x6.ld new file mode 100644 index 0000000..23f77f3 --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100x6.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x6, 32K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100x8.ld b/libopencm3/lib/stm32/f1/stm32f100x8.ld new file mode 100644 index 0000000..e0aa041 --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100x8.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x8, 64K flash, 8K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100xb.ld b/libopencm3/lib/stm32/f1/stm32f100xb.ld new file mode 100644 index 0000000..83d64fd --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100xb.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100xB, 128K flash, 8K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100xc.ld b/libopencm3/lib/stm32/f1/stm32f100xc.ld new file mode 100644 index 0000000..30a894a --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100xc.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100xC, 256K flash, 24K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 24K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100xd.ld b/libopencm3/lib/stm32/f1/stm32f100xd.ld new file mode 100644 index 0000000..b507435 --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100xd.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100xD, 384K flash, 32K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/stm32f100xe.ld b/libopencm3/lib/stm32/f1/stm32f100xe.ld new file mode 100644 index 0000000..a12d1ff --- /dev/null +++ b/libopencm3/lib/stm32/f1/stm32f100xe.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100xE, 512K flash, 32K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/libopencm3/lib/stm32/f1/timer.c b/libopencm3/lib/stm32/f1/timer.c new file mode 100644 index 0000000..fd46742 --- /dev/null +++ b/libopencm3/lib/stm32/f1/timer.c @@ -0,0 +1,57 @@ +/* This file is used for documentation purposes. It does not need +to be compiled. All source code is in the common area. +If there is any device specific code required it can be included here, +in which case this file must be added to the compile list. */ + +/** @defgroup timer_file Timers + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx Timers + +@version 1.0.0 + +@date 18 August 2012 + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set Input Polarity + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@param[in] ic ::tim_ic_id. Input Capture channel designator. +@param[in] pol ::tim_ic_pol. Input Capture polarity. +*/ + +void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic, + enum tim_ic_pol pol) +{ + if (pol) { + TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4)); + } else { + TIM_CCER(timer_peripheral) &= ~(0x2 << (ic * 4)); + } +} + diff --git a/libopencm3/lib/stm32/f1/usart.c b/libopencm3/lib/stm32/f1/usart.c new file mode 100644 index 0000000..84ae505 --- /dev/null +++ b/libopencm3/lib/stm32/f1/usart.c @@ -0,0 +1,31 @@ +/** @defgroup usart_file USART + +@ingroup STM32F1xx + +@brief libopencm3 STM32F1xx USART + +@version 1.0.0 + +@date 30 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/Makefile b/libopencm3/lib/stm32/f2/Makefile new file mode 100644 index 0000000..9291668 --- /dev/null +++ b/libopencm3/lib/stm32/f2/Makefile @@ -0,0 +1,52 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32f2 +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32F2 +# ARFLAGS = rcsv +ARFLAGS = rcs + +OBJS = gpio.o rcc.o + +OBJS += crc_common_all.o dac_common_all.o dma_common_f24.o \ + gpio_common_all.o gpio_common_f0234.o i2c_common_all.o \ + iwdg_common_all.o rtc_common_l1f024.o spi_common_all.o \ + spi_common_l1f124.o timer_common_all.o timer_common_f234.o \ + timer_common_f24.o usart_common_all.o usart_common_f124.o \ + flash_common_f234.o flash_common_f24.o hash_common_f24.o \ + crypto_common_f24.o exti_common_all.o rcc_common_all.o + +OBJS += usb.o usb_standard.o usb_control.o usb_fx07_common.o \ + usb_f107.o usb_f207.o usb_msc.o + +VPATH += ../../usb:../:../../cm3:../common + +include ../../Makefile.include diff --git a/libopencm3/lib/stm32/f2/crc.c b/libopencm3/lib/stm32/f2/crc.c new file mode 100644 index 0000000..c5ae5d3 --- /dev/null +++ b/libopencm3/lib/stm32/f2/crc.c @@ -0,0 +1,33 @@ +/** @defgroup crc_file CRC + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx CRC + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f2/crypto.c b/libopencm3/lib/stm32/f2/crypto.c new file mode 100644 index 0000000..e44fb63 --- /dev/null +++ b/libopencm3/lib/stm32/f2/crypto.c @@ -0,0 +1,31 @@ +/** @defgroup crypto_file CRYPTO + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx Cryptographic controller + * + * @version 1.0.0 + * + * @date 14 January 2014 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/dac.c b/libopencm3/lib/stm32/f2/dac.c new file mode 100644 index 0000000..635e142 --- /dev/null +++ b/libopencm3/lib/stm32/f2/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx DAC + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/dma.c b/libopencm3/lib/stm32/f2/dma.c new file mode 100644 index 0000000..285f1fe --- /dev/null +++ b/libopencm3/lib/stm32/f2/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx DMA + +@version 1.0.0 + +@date 30 November 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/flash.c b/libopencm3/lib/stm32/f2/flash.c new file mode 100644 index 0000000..7f8255d --- /dev/null +++ b/libopencm3/lib/stm32/f2/flash.c @@ -0,0 +1,53 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx FLASH + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * + * @date 14 January 2014 + * + * This library supports the FLASH memory controller in the STM32F2 + * series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * For the STM32F2xx, accessing FLASH memory is described briefly in + * section 2.3.3 of the STM32F2xx Reference Manual. + * For detailed programming information see: + * PM0059 programming manual: STM32F10xxx Flash programming + * June 2013, Doc ID DocID15687 Rev 5 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f2/gpio.c b/libopencm3/lib/stm32/f2/gpio.c new file mode 100644 index 0000000..052e306 --- /dev/null +++ b/libopencm3/lib/stm32/f2/gpio.c @@ -0,0 +1,31 @@ +/** @defgroup gpio_file GPIO + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx General Purpose I/O + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/hash.c b/libopencm3/lib/stm32/f2/hash.c new file mode 100644 index 0000000..ca48d8b --- /dev/null +++ b/libopencm3/lib/stm32/f2/hash.c @@ -0,0 +1,31 @@ +/** @defgroup hash_file HASH + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx Hash Processor + * + * @version 1.0.0 + * + * @date 14 January 2014 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/i2c.c b/libopencm3/lib/stm32/f2/i2c.c new file mode 100644 index 0000000..ea0c99d --- /dev/null +++ b/libopencm3/lib/stm32/f2/i2c.c @@ -0,0 +1,33 @@ +/** @defgroup i2c_file I2C + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx I2C + * + * @version 1.0.0 + * + * @date 15 October 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + diff --git a/libopencm3/lib/stm32/f2/iwdg.c b/libopencm3/lib/stm32/f2/iwdg.c new file mode 100644 index 0000000..2d9dc4a --- /dev/null +++ b/libopencm3/lib/stm32/f2/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx Independent Watchdog Timer + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld b/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/f2/pwr.c b/libopencm3/lib/stm32/f2/pwr.c new file mode 100644 index 0000000..0e5641e --- /dev/null +++ b/libopencm3/lib/stm32/f2/pwr.c @@ -0,0 +1,39 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx Power Control + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2014 + * Ken Sarkies + * + * @date 13 January 2014 + * + * This library supports the power control system for the + * STM32F4 series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + diff --git a/libopencm3/lib/stm32/f2/rcc.c b/libopencm3/lib/stm32/f2/rcc.c new file mode 100644 index 0000000..4b6195b --- /dev/null +++ b/libopencm3/lib/stm32/f2/rcc.c @@ -0,0 +1,417 @@ +/** @defgroup rcc_file RCC + * + * @ingroup STM32F2xx + * + * @section rcc_f2_api_ex Reset and Clock Control API. + * + * @brief libopencm3 STM32F2xx Reset and Clock Control + * + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 18 Jun 2013 + * + * This library supports the Reset and Clock Control System in the STM32 series + * of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + +/**@{*/ + +/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */ +uint32_t rcc_ppre1_frequency = 16000000; +uint32_t rcc_ppre2_frequency = 16000000; + +const clock_scale_t hse_8mhz_3v3[CLOCK_3V3_END] = { + { /* 120MHz */ + .pllm = 8, + .plln = 240, + .pllp = 2, + .pllq = 5, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 30000000, + .apb2_frequency = 60000000, + }, +}; + +void rcc_osc_ready_int_clear(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +void rcc_osc_ready_int_enable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +void rcc_osc_ready_int_disable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + } +} + +int rcc_osc_ready_int_flag(osc_t osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } + + cm3_assert_not_reached(); +} + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +void rcc_wait_for_osc_ready(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + +void rcc_wait_for_sysclk_status(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL); + break; + case HSE: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE); + break; + case HSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI); + break; + default: + /* Shouldn't be reached. */ + break; + } +} + +void rcc_osc_on(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +void rcc_osc_off(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +void rcc_osc_bypass_enable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_osc_bypass_disable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_set_sysclk_source(uint32_t clk) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | clk); +} + +void rcc_set_pll_source(uint32_t pllsrc) +{ + uint32_t reg32; + + reg32 = RCC_PLLCFGR; + reg32 &= ~(1 << 22); + RCC_PLLCFGR = (reg32 | (pllsrc << 22)); +} + +void rcc_set_ppre2(uint32_t ppre2) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15)); + RCC_CFGR = (reg32 | (ppre2 << 13)); +} + +void rcc_set_ppre1(uint32_t ppre1) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12)); + RCC_CFGR = (reg32 | (ppre1 << 10)); +} + +void rcc_set_hpre(uint32_t hpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); + RCC_CFGR = (reg32 | (hpre << 4)); +} + +void rcc_set_rtcpre(uint32_t rtcpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); + RCC_CFGR = (reg32 | (rtcpre << 16)); +} + +void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq) +{ + RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | + (plln << RCC_PLLCFGR_PLLN_SHIFT) | + (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + (pllq << RCC_PLLCFGR_PLLQ_SHIFT); +} + +void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq) +{ + RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | + (plln << RCC_PLLCFGR_PLLN_SHIFT) | + (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + RCC_PLLCFGR_PLLSRC | + (pllq << RCC_PLLCFGR_PLLQ_SHIFT); +} + +uint32_t rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return (RCC_CFGR & 0x000c) >> 2; +} + +void rcc_clock_setup_hse_3v3(const clock_scale_t *clock) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_HSI); + + /* Enable external high-speed oscillator 8MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre1(clock->ppre1); + rcc_set_ppre2(clock->ppre2); + + rcc_set_main_pll_hse(clock->pllm, clock->plln, + clock->pllp, clock->pllq); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_PLL); + + /* Wait for PLL clock to be selected. */ + rcc_wait_for_sysclk_status(PLL); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; +} + +void rcc_backupdomain_reset(void) +{ + /* Set the backup domain software reset. */ + RCC_BDCR |= RCC_BDCR_BDRST; + + /* Clear the backup domain software reset. */ + RCC_BDCR &= ~RCC_BDCR_BDRST; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/f2/rtc.c b/libopencm3/lib/stm32/f2/rtc.c new file mode 100644 index 0000000..06666ab --- /dev/null +++ b/libopencm3/lib/stm32/f2/rtc.c @@ -0,0 +1,31 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32F2xx + * + * @brief libopencm3 STM32F2xx RTC + * + * @version 1.0.0 + * + * @date 4 March 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/spi.c b/libopencm3/lib/stm32/f2/spi.c new file mode 100644 index 0000000..8fb70cd --- /dev/null +++ b/libopencm3/lib/stm32/f2/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx SPI + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/timer.c b/libopencm3/lib/stm32/f2/timer.c new file mode 100644 index 0000000..6600705 --- /dev/null +++ b/libopencm3/lib/stm32/f2/timer.c @@ -0,0 +1,38 @@ +/* This file is used for documentation purposes. It does not need +to be compiled. All source code is in the common area. +If there is any device specific code required it can be included here, +in which case this file must be added to the compile list. */ + +/** @defgroup timer_file Timers + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx Timers + +@version 1.0.0 + +@date 18 August 2012 + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f2/usart.c b/libopencm3/lib/stm32/f2/usart.c new file mode 100644 index 0000000..f6de5a8 --- /dev/null +++ b/libopencm3/lib/stm32/f2/usart.c @@ -0,0 +1,31 @@ +/** @defgroup usart_file USART + +@ingroup STM32F2xx + +@brief libopencm3 STM32F2xx USART + +@version 1.0.0 + +@date 30 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f3/Makefile b/libopencm3/lib/stm32/f3/Makefile new file mode 100644 index 0000000..5ef282a --- /dev/null +++ b/libopencm3/lib/stm32/f3/Makefile @@ -0,0 +1,50 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32f3 +SRCLIBDIR ?= ../.. + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32F3 + +ARFLAGS = rcs + +OBJS = rcc.o adc.o i2c.o usart.o dma.o flash.o + +OBJS += gpio_common_all.o gpio_common_f0234.o \ + dac_common_all.o usart_common_all.o crc_common_all.o\ + iwdg_common_all.o spi_common_all.o dma_common_l1f013.o\ + timer_common_all.o timer_common_f234.o flash_common_f234.o \ + flash.o exti_common_all.o rcc_common_all.o spi_common_f03.o + +OBJS += usb.o usb_control.o usb_standard.o usb_f103.o + +VPATH += ../../usb:../:../../cm3:../common + +include ../../Makefile.include diff --git a/libopencm3/lib/stm32/f3/adc.c b/libopencm3/lib/stm32/f3/adc.c new file mode 100644 index 0000000..805bf2e --- /dev/null +++ b/libopencm3/lib/stm32/f3/adc.c @@ -0,0 +1,1150 @@ +/** @defgroup adc_file ADC + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Analog to Digital Converters + * + * @author @htmlonly © @endhtmlonly 2012 + * Ken Sarkies + * + * @date 30 August 2012 + * + * This library supports the A/D Converter Control System in the STM32 series + * of ARM Cortex Microcontrollers by ST Microelectronics. + * + * Devices can have up to three A/D converters each with their own set of + * registers. However all the A/D converters share a common clock which is + * prescaled from the APB2 clock by default by a minimum factor of 2 to a + * maximum of 8. The ADC resolution can be set to 12, 10, 8 or 6 bits. + * + * Each A/D converter has up to 19 channels: + * @li On ADC1 the analog channels 16 is internally connected to the + * temperature sensor, channel 17 to VREFINT, and channel 18 + * to VBATT. + * @li On ADC2 and ADC3 the analog channels 16 - 18 are not used. + * + * The conversions can occur as a one-off conversion whereby the process stops + * once conversion is complete. The conversions can also be continuous wherein + * a new conversion starts immediately the previous conversion has ended. + * + * Conversion can occur as a single channel conversion or a scan of a group of + * channels in either continuous or one-off mode. If more than one channel is + * converted in a scan group, DMA must be used to transfer the data as there is + * only one result register available. An interrupt can be set to occur at the + * end* + * of conversion, which occurs after all channels have been scanned. + * + * A discontinuous mode allows a subgroup of group of a channels to be + * converted in bursts of a given length. + * + * Injected conversions allow a second group of channels to be converted + * separately from the regular group. An interrupt can be set to occur at the + * end of conversion, which occurs after all channels have been scanned. + * + * @section adc_f3_api_ex Basic ADC Handling API. + * + * Example 1: Simple single channel conversion polled. Enable the peripheral + * clock and ADC, reset ADC and set the prescaler divider. Set multiple mode to + * independent. + * + * @code + * gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1); + * rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); + * adc_set_clk_prescale(RCC_CFGR_ADCPRE_BY2); + * adc_disable_scan_mode(ADC1); + * adc_set_single_conversion_mode(ADC1); + * adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC); + * uint8_t channels[] = ADC_CHANNEL0; + * adc_set_regular_sequence(ADC1, 1, channels); + * adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT); + * adc_power_on(ADC1); + * adc_start_conversion_regular(ADC1); + * while (! adc_eoc(ADC1)); + * reg16 = adc_read_regular(ADC1); + * @endcode + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Off + * + * Turn off the ADC to reduce power consumption to a few microamps. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base +*/ + +void adc_off(uint32_t adc) +{ + ADC_CR(adc) &= ~ADC_CR_ADEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for Regular Conversions + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Comparison is done before + * data alignment takes place, so the thresholds are left-aligned. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_analog_watchdog_regular(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_AWD1EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for Regular Conversions + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Comparison is done before + * data alignment takes place, so the thresholds are left-aligned. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ +void adc_disable_analog_watchdog_regular(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_AWD1EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for Injected Conversions + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Comparison is done before + * data alignment takes place, so the thresholds are left-aligned. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_analog_watchdog_injected(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_JAWD1EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog for Injected Conversions + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_analog_watchdog_injected(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_JAWD1EN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Discontinuous Mode for Regular Conversions + * + * In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the + * defined regular channel group. The subgroup is defined by the number of + * consecutive channels to be converted. After a subgroup has been converted + * the next trigger will start conversion of the immediately following subgroup + * of the same length or until the whole group has all been converted. When the + * whole group has been converted, the next trigger will restart conversion of + * the subgroup at the beginning of the whole group. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base @param[in] length Unsigned int8. Number of channels in the + * group @ref adc_cr1_discnum + */ + +void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length) +{ + if ((length-1) > 7) { + return; + } + ADC_CFGR(adc) |= ADC_CFGR_DISCEN; + ADC_CFGR(adc) |= ((length-1) << ADC_CFGR_DISCNUM_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Discontinuous Mode for Regular Conversions + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_discontinuous_mode_regular(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_DISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Discontinuous Mode for Injected Conversions + * + * In this mode the ADC converts sequentially one channel of the defined group + * of injected channels, cycling back to the first channel in the group once + * the entire group has been converted. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_discontinuous_mode_injected(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_JDISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Discontinuous Mode for Injected Conversions + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_discontinuous_mode_injected(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_JDISCEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Automatic Injected Conversions + * + * The ADC converts a defined injected group of channels immediately after the + * regular channels have been converted. The external trigger on the injected + * channels is disabled as required. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_automatic_injected_group_conversion(uint32_t adc) +{ + adc_disable_external_trigger_injected(adc); + ADC_CFGR(adc) |= ADC_CFGR_JAUTO; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Automatic Injected Conversions + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_automatic_injected_group_conversion(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_JAUTO; +} +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Comparison is done before + * data alignment takes place, so the thresholds are left-aligned. + * + * @note The analog watchdog must be enabled for either or both of the regular + * or injected channels. If neither are enabled, the analog watchdog feature + * will be disabled. + * + * @ref adc_enable_analog_watchdog_injected, @ref + * adc_enable_analog_watchdog_regular. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_analog_watchdog_on_all_channels(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_AWD1SGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog for a Selected Channel + * + * The analog watchdog allows the monitoring of an analog signal between two + * threshold levels. The thresholds must be preset. Comparison is done before + * data alignment takes place, so the thresholds are left-aligned. + * + * @note The analog watchdog must be enabled for either or both of the regular + * or injected channels. If neither are enabled, the analog watchdog feature + * will be disabled. If both are enabled, the same channel number is monitored + * @ref adc_enable_analog_watchdog_injected, @ref + * adc_enable_analog_watchdog_regular. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + * @param[in] channel Unsigned int8. ADC channel numbe + * @ref adc_watchdog_channel + */ + +void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, + uint8_t channel) +{ + uint32_t reg32; + + reg32 = (ADC_CFGR(adc) & ~ADC_CFGR_AWD1CH_MASK); /* Clear bit [4:0]. */ + if (channel < 18) { + reg32 |= channel; + } + ADC_CFGR(adc) = reg32; + ADC_CFGR(adc) |= ADC_CFGR_AWD1SGL; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Scan Mode + * + * In this mode a conversion consists of a scan of the predefined set of + * channels, regular and injected, each channel conversion immediately + * following the previous one. It can use single, continuous or discontinuous + * mode. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +/* +void adc_enable_scan_mode(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_SCAN; +} +*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Scan Mode + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +/* +void adc_disable_scan_mode(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_SCAN; +} +*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Injected End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_eoc_interrupt_injected(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_JEOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Injected End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_eoc_interrupt_injected(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_JEOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Analog Watchdog Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_all_awd_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_AWD1IE; + ADC_IER(adc) |= ADC_IER_AWD2IE; + ADC_IER(adc) |= ADC_IER_AWD3IE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Analog Watchdog Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_all_awd_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_AWD1IE; + ADC_IER(adc) &= ~ADC_IER_AWD2IE; + ADC_IER(adc) &= ~ADC_IER_AWD3IE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Regular End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_eoc_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_EOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable Regular End-Of-Conversion Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_eoc_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_EOCIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Software Triggered Conversion on Regular Channels + * + * This starts conversion on a set of defined regular channels. It is cleared + * by hardware once conversion starts. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_start_conversion_regular(uint32_t adc) +{ + /* Start conversion on regular channels. */ + ADC_CR(adc) |= ADC_CR_ADSTART; + + /* Wait until the ADC starts the conversion. */ + while (ADC_CR(adc) & ADC_CR_ADSTART); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Software Triggered Conversion on Injected Channels + * + * This starts conversion on a set of defined injected channels. It is cleared + * by hardware once conversion starts. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_start_conversion_injected(uint32_t adc) +{ + /* Start conversion on injected channels. */ + ADC_CR(adc) |= ADC_CR_JADSTART; + + /* Wait until the ADC starts the conversion. */ + while (ADC_CR(adc) & ADC_CR_JADSTART); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Left Aligned + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_set_left_aligned(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Data as Right Aligned + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_set_right_aligned(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_ALIGN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable DMA Transfers + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_enable_dma(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable DMA Transfers + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_disable_dma(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_DMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Continuous Conversion Mode + * + * In this mode the ADC starts a new conversion of a single channel or a channel + * group immediately following completion of the previous channel group + * conversion. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_set_continuous_conversion_mode(uint32_t adc) +{ + ADC_CFGR(adc) |= ADC_CFGR_CONT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable Single Conversion Mode + * + * In this mode the ADC performs a conversion of one channel or a channel group + * and stops. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_set_single_conversion_mode(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_CONT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for a Single Channel + * + * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] channel Unsigned int8. ADC Channel integer 0..18 or from + * @ref adc_channel + * @param[in] time Unsigned int8. Sampling time selection from + * @ref adc_sample_rg + */ + +void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time) +{ + uint32_t reg32; + + if (channel < 10) { + reg32 = ADC_SMPR2(adc); + reg32 &= ~(0x7 << (channel * 3)); + reg32 |= (time << (channel * 3)); + ADC_SMPR2(adc) = reg32; + } else { + reg32 = ADC_SMPR1(adc); + reg32 &= ~(0x7 << ((channel - 10) * 3)); + reg32 |= (time << ((channel - 10) * 3)); + ADC_SMPR1(adc) = reg32; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for All Channels + * + * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, + * same for all channels. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] time Unsigned int8. Sampling time selection from + * @ref adc_sample_rg + */ + +void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time) +{ + uint8_t i; + uint32_t reg32 = 0; + + for (i = 0; i <= 9; i++) { + reg32 |= (time << (i * 3)); + } + ADC_SMPR2(adc) = reg32; + + for (i = 10; i <= 17; i++) { + reg32 |= (time << ((i - 10) * 3)); + } + ADC_SMPR1(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Upper Threshold + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] threshold Unsigned int8. Upper threshold value + */ + +void adc_set_watchdog_high_threshold(uint32_t adc, uint8_t threshold) +{ + uint32_t reg32 = 0; + + reg32 |= (threshold << 16); + reg32 &= ~0xff00ffff; /* Clear all bits above 8. */ + ADC_TR1(adc) = reg32; + ADC_TR2(adc) = reg32; + ADC_TR3(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Analog Watchdog Lower Threshold + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] threshold Unsigned int8. Lower threshold value + */ + +void adc_set_watchdog_low_threshold(uint32_t adc, uint8_t threshold) +{ + uint32_t reg32 = 0; + + reg32 = (uint32_t)threshold; + reg32 &= ~0xffffff00; /* Clear all bits above 8. */ + ADC_TR1(adc) = reg32; + ADC_TR2(adc) = reg32; + ADC_TR3(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set a Regular Channel Conversion Sequence + * + * Define a sequence of channels to be converted as a regular group with a + * length from 1 to 16 channels. If this is called during conversion, the + * current conversion is reset and conversion begins again with the newly + * defined group. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] length Unsigned int8. Number of channels in the group. + * @param[in] channel Unsigned int8[]. Set of channels in sequence, integers + * 0..18. + */ + +void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[]) +{ + uint32_t reg32_1 = 0, reg32_2 = 0, reg32_3 = 0, reg32_4 = 0; + uint8_t i = 0; + + /* Maximum sequence length is 16 channels. */ + if (length > 16) { + return; + } + + for (i = 1; i <= length; i++) { + if (i <= 4) { + reg32_1 |= (channel[i - 1] << (i * 6)); + } + if ((i > 4) & (i <= 9)) { + reg32_2 |= (channel[i - 1] << ((i - 4 - 1) * 6)); + } + if ((i > 9) & (i <= 14)) { + reg32_3 |= (channel[i - 1] << ((i - 9 - 1) * 6)); + } + if ((i > 14) & (i <= 16)) { + reg32_4 |= (channel[i - 1] << ((i - 14 - 1) * 6)); + } + } + reg32_1 |= ((length - 1) << ADC_SQR1_L_LSB); + + ADC_SQR1(adc) = reg32_1; + ADC_SQR2(adc) = reg32_2; + ADC_SQR3(adc) = reg32_3; + ADC_SQR4(adc) = reg32_4; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set an Injected Channel Conversion Sequence + * + * Defines a sequence of channels to be converted as an injected group with a + * length from 1 to 4 channels. If this is called during conversion, the current + * conversion is reset and conversion begins again with the newly defined group. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] length Unsigned int8. Number of channels in the group. + * @param[in] channel Unsigned int8[]. Set of channels in sequence, integers + * 0..18 + */ + +void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[]) +{ + uint32_t reg32 = 0; + uint8_t i = 0; + + /* Maximum sequence length is 4 channels. Minimum sequence is 1.*/ + if ((length - 1) > 3) { + return; + } + + for (i = 0; i < length; i++) { + reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]); + } + + reg32 |= ADC_JSQR_JL_VAL(length); + + ADC_JSQR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the End-of-Conversion Flag + * + * This flag is set after all channels of a regular or injected group have been + * converted. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @returns bool. End of conversion flag. + */ + +bool adc_eoc(uint32_t adc) +{ + return ((ADC_ISR(adc) & ADC_ISR_EOC) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion + * + * This flag is set after all channels of an injected group have been + * converted. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @returns bool. End of conversion flag. + */ + +bool adc_eoc_injected(uint32_t adc) +{ + return ((ADC_ISR(adc) & ADC_ISR_JEOC) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read from the Regular Conversion Result Register + * + * The result read back is 12 bits, right or left aligned within the first + * 16 bits. For ADC1 only, the higher 16 bits will hold the result from ADC2 if + * an appropriate dual mode has been set @see adc_set_dual_mode. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @returns Unsigned int32 conversion result. + */ + +uint32_t adc_read_regular(uint32_t adc) +{ + return ADC_DR(adc); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read from an Injected Conversion Result Register + * + * The result read back from the selected injected result register (one of four) + * is 12 bits, right or left aligned within the first 16 bits. The result can + * have a negative value if the injected channel offset has been set @see + * adc_set_injected_offset. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + * @param[in] reg Unsigned int8. Register number (1 ... 4). + * @returns Unsigned int32 conversion result. + */ + +uint32_t adc_read_injected(uint32_t adc, uint8_t reg) +{ + switch (reg) { + case 1: + return ADC_JDR1(adc); + case 2: + return ADC_JDR2(adc); + case 3: + return ADC_JDR3(adc); + case 4: + return ADC_JDR4(adc); + } + return 0; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Injected Channel Data Offset + * + * This value is subtracted from the injected channel results after conversion + * is complete, and can result in negative results. A separate value can be + * specified for each injected data register. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] reg Unsigned int8. Register number (1 ... 4). + * @param[in] offset Unsigned int32. +*/ + +void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset) +{ + switch (reg) { + case 1: + ADC_OFR1(adc) |= ADC_OFR1_OFFSET1_EN; + ADC_OFR1(adc) |= offset; + break; + case 2: + ADC_OFR2(adc) |= ADC_OFR2_OFFSET2_EN; + ADC_OFR2(adc) |= offset; + break; + case 3: + ADC_OFR3(adc) |= ADC_OFR3_OFFSET3_EN; + ADC_OFR3(adc) |= offset; + break; + case 4: + ADC_OFR4(adc) |= ADC_OFR4_OFFSET4_EN; + ADC_OFR4(adc) |= offset; + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + * + * If the ADC is in power-down mode then it is powered up. The application + * needs to wait a time of about 3 microseconds for stabilization before using + * the ADC. If the ADC is already on this function call will have no effect. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_power_on(uint32_t adc) +{ + ADC_CR(adc) |= ADC_CR_ADEN; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Clock Prescale + * + * The ADC clock taken from the APB2 clock can be scaled down by 2, 4, 6 or 8. + * + * @param[in] prescale Unsigned int32. Prescale value for ADC Clock @ref + * adc_ccr_adcpre +*/ + +void adc_set_clk_prescale(uint32_t prescale) +{ + uint32_t reg32 = ((ADC_CCR & ~ADC_CCR_CKMODE_MASK) | prescale); + ADC_CCR = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Dual/Triple Mode + * + * The multiple mode uses ADC1 as master, ADC2 and optionally ADC3 in a slave + * arrangement. This setting is applied to ADC1 only. + * + * The various modes possible are described in the reference manual. + * + * @param[in] mode Unsigned int32. Multiple mode selection from @ref + * adc_multi_mode +*/ + +void adc_set_multi_mode(uint32_t mode) +{ + ADC_CCR |= mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Regular Channels + * + * This enables an external trigger for set of defined regular channels, and + * sets the polarity of the trigger event: rising or falling edge or both. Note + * that if the trigger polarity is zero, triggering is disabled. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + * @param[in] trigger Unsigned int32. Trigger identifier + * @ref adc_trigger_regular + * @param[in] polarity Unsigned int32. Trigger polarity @ref + * adc_trigger_polarity_regular + */ + +void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_CFGR(adc); + + reg32 &= ~(ADC_CFGR_EXTSEL_MASK | ADC_CFGR_EXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_CFGR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Regular Channels + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_disable_external_trigger_regular(uint32_t adc) +{ + ADC_CFGR(adc) &= ~ADC_CFGR_EXTEN_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Injected Channels + * + * This enables an external trigger for set of defined injected channels, and + * sets the polarity of the trigger event: rising or falling edge or both. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @param[in] trigger Unsigned int8. Trigger identifier + * @ref adc_trigger_injected + * @param[in] polarity Unsigned int32. Trigger polarity + * @ref adc_trigger_polarity_injected +*/ + +void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_JSQR(adc); + + reg32 &= ~(ADC_JSQR_JEXTSEL_MASK | ADC_JSQR_JEXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_JSQR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Injected Channels + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_external_trigger_injected(uint32_t adc) +{ + ADC_JSQR(adc) &= ~ADC_JSQR_JEXTEN_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Resolution + * + * ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a + * corresponding reduction in conversion time (resolution + 3 ADC clock cycles). + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + * @param[in] resolution Unsigned int8. Resolution value @ref adc_cr1_res + */ + +void adc_set_resolution(uint32_t adc, uint16_t resolution) +{ + uint32_t reg32 = ADC_CFGR(adc); + + reg32 &= ~ADC_CFGR_RES_MASK; + reg32 |= resolution; + ADC_CFGR(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable the Overrun Interrupt + * + * The overrun interrupt is generated when data is not read from a result + * register before the next conversion is written. If DMA is enabled, all + * transfers are terminated and any conversion sequence is aborted. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_overrun_interrupt(uint32_t adc) +{ + ADC_IER(adc) |= ADC_IER_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable the Overrun Interrupt + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_overrun_interrupt(uint32_t adc) +{ + ADC_IER(adc) &= ~ADC_IER_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Overrun Flag + * + * The overrun flag is set when data is not read from a result register before + * the next conversion is written. If DMA is enabled, all transfers are + * terminated and any conversion sequence is aborted. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + * @returns Unsigned int32 conversion result. + */ + +bool adc_get_overrun_flag(uint32_t adc) +{ + return ADC_ISR(adc) & ADC_ISR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Clear Overrun Flags + * + * The overrun flag is cleared. Note that if an overrun occurs, DMA is + * terminated. + * The flag must be cleared and the DMA stream and ADC reinitialised to resume + * conversions (see the reference manual). + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @returns Unsigned int32 conversion result. + */ + +void adc_clear_overrun_flag(uint32_t adc) +{ +/* need to write zero to clear this */ + ADC_ISR(adc) &= ~ADC_ISR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an EOC for Each Conversion + * + * The EOC is set after each conversion in a sequence rather than at the end of + * the sequence. Overrun detection is enabled only if DMA is enabled. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +void adc_eoc_after_each(uint32_t adc) +{ + ADC_ISR(adc) |= ADC_ISR_EOS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable the EOC for Each Conversion + * + * The EOC is set at the end of each sequence rather than after each conversion + * in the sequence. Overrun detection is enabled always. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_eoc_after_group(uint32_t adc) +{ + ADC_ISR(adc) &= ~ADC_ISR_EOS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set DMA to Continue + * + * This must be set to allow DMA to continue to operate after the last + * conversion in the DMA sequence. This allows DMA to be used in continuous + * circular mode. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +/* +void adc_set_dma_continue(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_DDS; +} +*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set DMA to Terminate + * + * This must be set to allow DMA to terminate after the last conversion in the + * DMA sequence. This can avoid overrun errors. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + */ + +/* +void adc_set_dma_terminate(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_DDS; +} +*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Analog Watchdog Flag + * + * This flag is set when the converted voltage crosses the high or low + * thresholds. + * + * @param[in] adc Unsigned int32. ADC block register address base + * @ref adc_reg_base + * @returns bool. AWD flag. + */ + +bool adc_awd(uint32_t adc) +{ + return (ADC_ISR(adc) & ADC_ISR_AWD1) && + (ADC_ISR(adc) & ADC_ISR_AWD2) && + (ADC_ISR(adc) & ADC_ISR_AWD3); +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The Temperature Sensor + * + * This enables both the sensor and the reference voltage measurements on + * channels + * 16 and 17. These are only available on ADC1 channel 16 and 17 respectively. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_enable_temperature_sensor() +{ + ADC_CCR |= ADC_CCR_TSEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The Temperature Sensor + * + * Disabling this will reduce power consumption from the sensor and the + * reference voltage measurements. + * + * @param[in] adc Unsigned int32. ADC block register address base @ref + * adc_reg_base + */ + +void adc_disable_temperature_sensor() +{ + ADC_CCR &= ~ADC_CCR_TSEN; +} + +/*---------------------------------------------------------------------------*/ + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f3/crc.c b/libopencm3/lib/stm32/f3/crc.c new file mode 100644 index 0000000..eb3c14b --- /dev/null +++ b/libopencm3/lib/stm32/f3/crc.c @@ -0,0 +1,33 @@ +/** @defgroup crc_file CRC + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx CRC + * + * @version 1.0.0 + * + * @date 15 October 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f3/dac.c b/libopencm3/lib/stm32/f3/dac.c new file mode 100644 index 0000000..2d8021e --- /dev/null +++ b/libopencm3/lib/stm32/f3/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx DAC + * + * @version 1.0.0 + * + * @date 18 August 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f3/dma.c b/libopencm3/lib/stm32/f3/dma.c new file mode 100644 index 0000000..c5d82b1 --- /dev/null +++ b/libopencm3/lib/stm32/f3/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Direct Memory Access + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f3/flash.c b/libopencm3/lib/stm32/f3/flash.c new file mode 100644 index 0000000..d157aca --- /dev/null +++ b/libopencm3/lib/stm32/f3/flash.c @@ -0,0 +1,63 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx FLASH + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * + * @date 14 January 2014 + * + * This library supports the FLASH memory controller in the STM32F3 + * series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * For the STM32F3xx, accessing FLASH memory is described in + * section 3 of the STM32F3xx Reference Manual. + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Clear All Status Flags + +Clears program error, end of operation, busy flags. +*/ + +void flash_clear_status_flags(void) +{ + flash_clear_pgperr_flag(); + flash_clear_eop_flag(); + flash_clear_bsy_flag(); +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/f3/i2c.c b/libopencm3/lib/stm32/f3/i2c.c new file mode 100644 index 0000000..b5d39cf --- /dev/null +++ b/libopencm3/lib/stm32/f3/i2c.c @@ -0,0 +1,486 @@ +/** @defgroup i2c_file I2C + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx I2C + * + * @version 1.0.0 + * + * @date 15 October 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Reset. + * + * The I2C peripheral and all its associated configuration registers are placed + * in the reset condition. The reset is effected via the RCC peripheral reset + * system. + * + * @param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base. + */ + +void i2c_reset(uint32_t i2c) +{ + switch (i2c) { + case I2C1: + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST); + break; + case I2C2: + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST); + break; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Peripheral Enable. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ + +void i2c_peripheral_enable(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_PE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Peripheral Disable. + * + * This must not be reset while in Master mode until a communication has + * finished. In Slave mode, the peripheral is disabled only after communication + * has ended. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ + +void i2c_peripheral_disable(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_PE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Start Condition. + * + * If in Master mode this will cause a restart condition to occur at the end of + * the current transmission. If in Slave mode, this will initiate a start + * condition when the current bus activity is completed. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ + +void i2c_send_start(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_START; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Stop Condition. + * + * After the current byte transfer this will initiate a stop condition if in + * Master mode, or simply release the bus if in Slave mode. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ + +void i2c_send_stop(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_STOP; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Clear Stop Flag. + * + * Clear the "Send Stop" flag in the I2C config register + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +void i2c_clear_stop(uint32_t i2c) +{ + I2C_ICR(i2c) |= I2C_ICR_STOPCF; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set the 7 bit Slave Address for the Peripheral. + * + * This sets an address for Slave mode operation, in 7 bit form. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + * @param[in] slave Unsigned int8. Slave address 0...127. + */ + +void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave) +{ + I2C_OAR1(i2c) = (uint16_t)(slave << 1); + I2C_OAR1(i2c) &= ~I2C_OAR1_OA1MODE; + I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Set the 10 bit Slave Address for the Peripheral. + * + * This sets an address for Slave mode operation, in 10 bit form. + * + * @todo add "I2C_OAR1(i2c) |= (1 << 14);" as above + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + * @param[in] slave Unsigned int16. Slave address 0...1023. + */ + +void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave) +{ + I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_OA1MODE | slave); +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Send Data. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + * @param[in] data Unsigned int8. Byte to send. + */ + +void i2c_send_data(uint32_t i2c, uint8_t data) +{ + I2C_TXDR(i2c) = data; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Get Data. + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +uint8_t i2c_get_data(uint32_t i2c) +{ + return I2C_RXDR(i2c) & 0xff; +} + +void i2c_enable_analog_filter(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_ANFOFF; +} + +void i2c_disable_analog_filter(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_ANFOFF; +} + +void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting) +{ + I2C_CR1(i2c) = (I2C_CR1(i2c) & ~I2C_CR1_DNF_MASK) | dnf_setting; +} + +/* t_presc= (presc+1)*t_i2cclk */ +void i2c_set_prescaler(uint32_t i2c, uint8_t presc) +{ + I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_PRESC_MASK) | + (presc << I2C_TIMINGR_PRESC_SHIFT); +} + +void i2c_set_data_setup_time(uint32_t i2c, uint8_t s_time) +{ + I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLDEL_MASK) | + (s_time << I2C_TIMINGR_SCLDEL_SHIFT); +} + +void i2c_set_data_hold_time(uint32_t i2c, uint8_t h_time) +{ + I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SDADEL_MASK) | + (h_time << I2C_TIMINGR_SDADEL_SHIFT); +} + +void i2c_set_scl_high_period(uint32_t i2c, uint8_t period) +{ + I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLH_MASK) | + (period << I2C_TIMINGR_SCLH_SHIFT); +} + +void i2c_set_scl_low_period(uint32_t i2c, uint8_t period) +{ + I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLL_MASK) | + (period << I2C_TIMINGR_SCLL_SHIFT); +} + +void i2c_enable_stretching(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_NOSTRETCH; +} + +void i2c_disable_stretching(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_NOSTRETCH; +} + +void i2c_100khz_i2cclk8mhz(uint32_t i2c) +{ + i2c_set_prescaler(i2c, 1); + i2c_set_scl_low_period(i2c, 0x13); + i2c_set_scl_high_period(i2c, 0xF); + i2c_set_data_hold_time(i2c, 0x2); + i2c_set_data_setup_time(i2c, 0x4); +} + +void i2c_set_7bit_addr_mode(uint32_t i2c) +{ + I2C_CR2(i2c) &= ~I2C_CR2_ADD10; +} + +void i2c_set_10bit_addr_mode(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_ADD10; +} + +void i2c_set_7bit_address(uint32_t i2c, uint8_t addr) +{ + I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_7BIT_MASK) | + ((addr & 0x7F) << I2C_CR2_SADD_7BIT_SHIFT); +} + +void i2c_set_10bit_address(uint32_t i2c, uint16_t addr) +{ + I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_10BIT_MASK) | + ((addr & 0x3FF) << I2C_CR2_SADD_10BIT_SHIFT); +} + +void i2c_set_write_transfer_dir(uint32_t i2c) +{ + I2C_CR2(i2c) &= ~I2C_CR2_RD_WRN; +} + +void i2c_set_read_transfer_dir(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_RD_WRN; +} + +void i2c_set_bytes_to_transfer(uint32_t i2c, uint32_t n_bytes) +{ + I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_NBYTES_MASK) | + (n_bytes << I2C_CR2_NBYTES_SHIFT); +} + +uint8_t i2c_is_start(uint32_t i2c) +{ + if ((I2C_CR2(i2c) & I2C_CR2_START) != 0) { + return 1; + } + + return 0; +} + +void i2c_enable_autoend(uint32_t i2c) +{ + I2C_CR2(i2c) |= I2C_CR2_AUTOEND; +} + +void i2c_disable_autoend(uint32_t i2c) +{ + I2C_CR2(i2c) &= ~I2C_CR2_AUTOEND; +} + +uint8_t i2c_nack(uint32_t i2c) +{ + if ((I2C_ISR(i2c) & I2C_ISR_NACKF) != 0) { + return 1; + } + + return 0; +} + +uint8_t i2c_busy(uint32_t i2c) +{ + if ((I2C_ISR(i2c) & I2C_ISR_BUSY) != 0) { + return 1; + } + + return 0; +} + +uint8_t i2c_transmit_int_status(uint32_t i2c) +{ + if ((I2C_ISR(i2c) & I2C_ISR_TXIS) != 0) { + return 1; + } + + return 0; +} + +uint8_t i2c_transfer_complete(uint32_t i2c) +{ + if ((I2C_ISR(i2c) & I2C_ISR_TC) != 0) { + return 1; + } + + return 0; +} + +uint8_t i2c_received_data(uint32_t i2c) +{ + if ((I2C_ISR(i2c) & I2C_ISR_RXNE) != 0) { + return 1; + } + + return 0; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable Interrupt + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + * @param[in] interrupt Unsigned int32. Interrupt to enable. + */ +void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt) +{ + I2C_CR1(i2c) |= interrupt; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable Interrupt + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + * @param[in] interrupt Unsigned int32. Interrupt to disable. + */ +void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt) +{ + I2C_CR1(i2c) &= ~interrupt; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable reception DMA + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +void i2c_enable_rxdma(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_RXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable reception DMA + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +void i2c_disable_rxdma(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_RXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Enable transmission DMA + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +void i2c_enable_txdma(uint32_t i2c) +{ + I2C_CR1(i2c) |= I2C_CR1_TXDMAEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief I2C Disable transmission DMA + * + * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. + */ +void i2c_disable_txdma(uint32_t i2c) +{ + I2C_CR1(i2c) &= ~I2C_CR1_TXDMAEN; +} + +void write_i2c(uint32_t i2c, uint8_t i2c_addr, uint8_t reg, uint8_t size, + uint8_t *data) +{ + int wait; + int i; + while (i2c_busy(i2c) == 1); + while (i2c_is_start(i2c) == 1); + /*Setting transfer properties*/ + i2c_set_bytes_to_transfer(i2c, size + 1); + i2c_set_7bit_address(i2c, (i2c_addr & 0x7F)); + i2c_set_write_transfer_dir(i2c); + i2c_enable_autoend(i2c); + /*start transfer*/ + i2c_send_start(i2c); + + wait = true; + while (wait) { + if (i2c_transmit_int_status(i2c)) { + wait = false; + } + while (i2c_nack(i2c)); + } + + i2c_send_data(i2c, reg); + for (i = 0; i < size; i++) { + wait = true; + while (wait) { + if (i2c_transmit_int_status(i2c)) { + wait = false; + } + while (i2c_nack(i2c)); + } + i2c_send_data(i2c, data[i]); + } +} + +void read_i2c(uint32_t i2c, uint8_t i2c_addr, uint8_t reg, uint8_t size, + uint8_t *data) +{ + int wait; + int i; + while (i2c_busy(i2c) == 1); + while (i2c_is_start(i2c) == 1); + /*Setting transfer properties*/ + i2c_set_bytes_to_transfer(i2c, 1); + i2c_set_7bit_address(i2c, i2c_addr); + i2c_set_write_transfer_dir(i2c); + i2c_disable_autoend(i2c); + /*start transfer*/ + i2c_send_start(i2c); + + wait = true; + while (wait) { + if (i2c_transmit_int_status(i2c)) { + wait = false; + } + while (i2c_nack(i2c)); /* Some error */ + } + i2c_send_data(i2c, reg); + + while (i2c_is_start(i2c) == 1); + /*Setting transfer properties*/ + i2c_set_bytes_to_transfer(i2c, size); + i2c_set_7bit_address(i2c, i2c_addr); + i2c_set_read_transfer_dir(i2c); + i2c_enable_autoend(i2c); + /*start transfer*/ + i2c_send_start(i2c); + + for (i = 0; i < size; i++) { + while (i2c_received_data(i2c) == 0); + data[i] = i2c_get_data(i2c); + } +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/f3/iwdg.c b/libopencm3/lib/stm32/f3/iwdg.c new file mode 100644 index 0000000..cf0045c --- /dev/null +++ b/libopencm3/lib/stm32/f3/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Independent Watchdog Timer + * + * @version 1.0.0 + * + * @date 18 August 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld b/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/f3/pwr.c b/libopencm3/lib/stm32/f3/pwr.c new file mode 100644 index 0000000..3c1a84b --- /dev/null +++ b/libopencm3/lib/stm32/f3/pwr.c @@ -0,0 +1,40 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Power Control + * + * @author @htmlonly © @endhtmlonly 2014 + * Ken Sarkies + * + * @date 13 January 2014 + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f3/rcc.c b/libopencm3/lib/stm32/f3/rcc.c new file mode 100644 index 0000000..8291a2b --- /dev/null +++ b/libopencm3/lib/stm32/f3/rcc.c @@ -0,0 +1,465 @@ +/** @defgroup rcc_file RCC + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Reset and Clock Control + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * Modified by 2013 Fernando Cortes (stm32f3) + * Modified by 2013 Guillermo Rivera (stm32f3) + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ + +#include +#include +#include +#include + +/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */ +uint32_t rcc_ppre1_frequency = 8000000; +uint32_t rcc_ppre2_frequency = 8000000; + +const clock_scale_t hsi_8mhz[CLOCK_END] = { + { /* 44MHz */ + .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X11, + .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE1_DIV_2, + .ppre2 = RCC_CFGR_PPRE2_DIV_NONE, + .power_save = 1, + .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1WS, + .apb1_frequency = 22000000, + .apb2_frequency = 44000000, + }, + { /* 48MHz */ + .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X12, + .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE1_DIV_2, + .ppre2 = RCC_CFGR_PPRE2_DIV_NONE, + .power_save = 1, + .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1WS, + .apb1_frequency = 24000000, + .apb2_frequency = 48000000, + }, + { /* 64MHz */ + .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X16, + .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE1_DIV_2, + .ppre2 = RCC_CFGR_PPRE2_DIV_NONE, + .power_save = 1, + .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2WS, + .apb1_frequency = 32000000, + .apb2_frequency = 64000000, + } +}; + +void rcc_osc_ready_int_clear(enum osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +void rcc_osc_ready_int_enable(enum osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +void rcc_osc_ready_int_disable(enum osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + } +} + +int rcc_osc_ready_int_flag(enum osc osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } + + cm3_assert_not_reached(); +} + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +void rcc_wait_for_osc_ready(enum osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + + +void rcc_wait_for_osc_not_ready(enum osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) != 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) != 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) != 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) != 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) != 0); + break; + } +} + +void rcc_wait_for_sysclk_status(enum osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL); + break; + case HSE: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE); + break; + case HSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI); + break; + default: + /* Shouldn't be reached. */ + break; + } +} + +void rcc_osc_on(enum osc osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +void rcc_osc_off(enum osc osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +void rcc_osc_bypass_enable(enum osc osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_osc_bypass_disable(enum osc osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_set_sysclk_source(uint32_t clk) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | clk); +} + +void rcc_set_pll_source(uint32_t pllsrc) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~RCC_CFGR_PLLSRC; + RCC_CFGR = (reg32 | (pllsrc << 16)); +} + +void rcc_set_ppre2(uint32_t ppre2) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15)); + RCC_CFGR = (reg32 | (ppre2 << 11)); +} + +void rcc_set_ppre1(uint32_t ppre1) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12)); + RCC_CFGR = (reg32 | (ppre1 << 8)); +} + +void rcc_set_hpre(uint32_t hpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); + RCC_CFGR = (reg32 | (hpre << 4)); +} + + +void rcc_set_main_pll_hsi(uint32_t pll) +{ + RCC_CFGR = (~RCC_CFGR_PLLMUL_MASK & RCC_CFGR) | + (pll << RCC_CFGR_PLLMUL_SHIFT); +} + + +uint32_t rcc_get_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return (RCC_CFGR & 0x000c) >> 2; +} + + +void rcc_clock_setup_hsi(const clock_scale_t *clock) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_HSI); /* XXX: se cayo */ + rcc_wait_for_sysclk_status(HSI); + + rcc_osc_off(PLL); + rcc_wait_for_osc_not_ready(PLL); + rcc_set_pll_source(clock->pllsrc); + rcc_set_main_pll_hsi(clock->pll); + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre2(clock->ppre2); + rcc_set_ppre1(clock->ppre1); + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_PLL); /* XXX: se cayo */ + /* Wait for PLL clock to be selected. */ + rcc_wait_for_sysclk_status(PLL); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; +} + + +void rcc_backupdomain_reset(void) +{ + /* Set the backup domain software reset. */ + RCC_BDCR |= RCC_BDCR_BDRST; + + /* Clear the backup domain software reset. */ + RCC_BDCR &= ~RCC_BDCR_BDRST; +} + +void rcc_set_i2c_clock_hsi(uint32_t i2c) +{ + if (i2c == I2C1) { + RCC_CFGR3 &= ~RCC_CFGR3_I2C1SW; + } + if (i2c == I2C2) { + RCC_CFGR3 &= ~RCC_CFGR3_I2C2SW; + } +} + +void rcc_set_i2c_clock_sysclk(uint32_t i2c) +{ + if (i2c == I2C1) { + RCC_CFGR3 |= RCC_CFGR3_I2C1SW; + } + if (i2c == I2C2) { + RCC_CFGR3 |= RCC_CFGR3_I2C2SW; + } +} + +uint32_t rcc_get_i2c_clocks(void) +{ + return RCC_CFGR3 & (RCC_CFGR3_I2C1SW | RCC_CFGR3_I2C2SW); +} + +void rcc_usb_prescale_1_5(void) +{ + RCC_CFGR &= ~RCC_CFGR_USBPRES; +} + +void rcc_usb_prescale_1(void) +{ + RCC_CFGR |= RCC_CFGR_USBPRES; +} +/**@}*/ + diff --git a/libopencm3/lib/stm32/f3/rtc.c b/libopencm3/lib/stm32/f3/rtc.c new file mode 100644 index 0000000..f332765 --- /dev/null +++ b/libopencm3/lib/stm32/f3/rtc.c @@ -0,0 +1,38 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Real Time Clock + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2014 + * Ken Sarkies + * + * @date 13 January 2014 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f3/spi.c b/libopencm3/lib/stm32/f3/spi.c new file mode 100644 index 0000000..3dcc524 --- /dev/null +++ b/libopencm3/lib/stm32/f3/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32F3xx + +@brief libopencm3 STM32F3xx SPI + +@version 1.0.0 + +@date 20 February 2014 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f3/timer.c b/libopencm3/lib/stm32/f3/timer.c new file mode 100644 index 0000000..0e9ac3d --- /dev/null +++ b/libopencm3/lib/stm32/f3/timer.c @@ -0,0 +1,33 @@ +/** @defgroup timer_file TIMER + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx Timers + * + * @version 1.0.0 + * + * @date 11 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f3/usart.c b/libopencm3/lib/stm32/f3/usart.c new file mode 100644 index 0000000..305ae72 --- /dev/null +++ b/libopencm3/lib/stm32/f3/usart.c @@ -0,0 +1,140 @@ +/** @defgroup usart_file USART + * + * @ingroup STM32F3xx + * + * @brief libopencm3 STM32F3xx USART + * + * @version 1.0.0 + * + * @date 30 August 2012 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief USART Send a Data Word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] data unsigned 16 bit. + */ + +void usart_send(uint32_t usart, uint16_t data) +{ + /* Send data. */ + USART_TDR(usart) = (data & USART_TDR_MASK); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Received Data Word. + * + * If parity is enabled the MSB (bit 7 or 8 depending on the word length) is + * the parity bit. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @returns unsigned 16 bit data word. + */ + +uint16_t usart_recv(uint32_t usart) +{ + /* Receive data. */ + return USART_RDR(usart) & USART_RDR_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Transmit Data Buffer Empty + * + * Blocks until the transmit data buffer becomes empty and is ready to accept + * the next data word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_wait_send_ready(uint32_t usart) +{ + /* Wait until the data has been transferred into the shift register. */ + while ((USART_ISR(usart) & USART_ISR_TXE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Wait for Received Data Available + * + * Blocks until the receive data buffer holds a valid received data word. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + */ + +void usart_wait_recv_ready(uint32_t usart) +{ + /* Wait until the data is ready to be received. */ + while ((USART_ISR(usart) & USART_ISR_RXNE) == 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Read a Status Flag. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. + * @returns boolean: flag set. + */ + +bool usart_get_flag(uint32_t usart, uint32_t flag) +{ + return ((USART_ISR(usart) & flag) != 0); +} + +/*---------------------------------------------------------------------------*/ +/** @brief USART Return Interrupt Source. + * + * Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was + * set and the interrupt was enabled. If the specified flag is not an interrupt + * flag, the function returns false. + * + * @todo These are the most important interrupts likely to be used. Others + * relating to LIN break, and error conditions in multibuffer communication, + * need to be added for completeness. + * + * @param[in] usart unsigned 32 bit. USART block register address base @ref + * usart_reg_base + * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags. + * @returns boolean: flag and interrupt enable both set. + */ + +bool usart_get_interrupt_source(uint32_t usart, uint32_t flag) +{ + uint32_t flag_set = (USART_ISR(usart) & flag); + /* IDLE, RXNE, TC, TXE interrupts */ + if ((flag >= USART_ISR_IDLE) && (flag <= USART_ISR_TXE)) { + return ((flag_set & USART_CR1(usart)) != 0); + /* Overrun error */ + } else if (flag == USART_ISR_ORE) { + return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE); + } + + return false; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/f3/vector_chipset.c b/libopencm3/lib/stm32/f3/vector_chipset.c new file mode 100644 index 0000000..145be05 --- /dev/null +++ b/libopencm3/lib/stm32/f3/vector_chipset.c @@ -0,0 +1,27 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * Copyright (C) 2011 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +static void pre_main(void) +{ + /* Enable access to Floating-Point coprocessor. */ + SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11); +} diff --git a/libopencm3/lib/stm32/f4/Makefile b/libopencm3/lib/stm32/f4/Makefile new file mode 100644 index 0000000..475d917 --- /dev/null +++ b/libopencm3/lib/stm32/f4/Makefile @@ -0,0 +1,59 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2013 Alexandru Gagniuc +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32f4 +SRCLIBDIR ?= ../.. + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m4 -mthumb $(FP_FLAGS) \ + -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32F4 +# ARFLAGS = rcsv +ARFLAGS = rcs + +OBJS = adc.o adc_common_v1.o can.o gpio.o pwr.o rcc.o rtc.o crypto.o + +OBJS += crc_common_all.o dac_common_all.o dma_common_f24.o \ + gpio_common_all.o gpio_common_f0234.o i2c_common_all.o \ + iwdg_common_all.o pwr_common_all.o rtc_common_l1f024.o \ + spi_common_all.o spi_common_l1f124.o timer_common_all.o \ + timer_common_f234.o timer_common_f24.o usart_common_all.o \ + usart_common_f124.o flash_common_f234.o flash_common_f24.o \ + hash_common_f24.o crypto_common_f24.o exti_common_all.o \ + rcc_common_all.o + +OBJS += usb.o usb_standard.o usb_control.o usb_fx07_common.o \ + usb_f107.o usb_f207.o usb_msc.o + +OBJS += mac.o phy.o mac_stm32fxx7.o phy_ksz8051mll.o fmc.o + +VPATH += ../../usb:../:../../cm3:../common +VPATH += ../../ethernet + +include ../../Makefile.include diff --git a/libopencm3/lib/stm32/f4/adc.c b/libopencm3/lib/stm32/f4/adc.c new file mode 100644 index 0000000..fba88de --- /dev/null +++ b/libopencm3/lib/stm32/f4/adc.c @@ -0,0 +1,437 @@ +/** @defgroup adc_file ADC + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx Analog to Digital Converters + +@author @htmlonly © @endhtmlonly 2012 +Ken Sarkies + +@date 30 August 2012 + +This library supports the A/D Converter Control System in the STM32 series +of ARM Cortex Microcontrollers by ST Microelectronics. + +Devices can have up to three A/D converters each with their own set of +registers. However all the A/D converters share a common clock which is +prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum +of 8. The ADC resolution can be set to 12, 10, 8 or 6 bits. + +Each A/D converter has up to 19 channels: +@li On ADC1 the analog channels 16 is internally connected to the temperature +sensor, channel 17 to VREFINT, and channel 18 to VBATT. +@li On ADC2 and ADC3 the analog channels 16 - 18 are not used. + +The conversions can occur as a one-off conversion whereby the process stops +once conversion is complete. The conversions can also be continuous wherein a +new conversion starts immediately the previous conversion has ended. + +Conversion can occur as a single channel conversion or a scan of a group of +channels in either continuous or one-off mode. If more than one channel is +converted in a scan group, DMA must be used to transfer the data as there is +only one result register available. An interrupt can be set to occur at the end +of conversion, which occurs after all channels have been scanned. + +A discontinuous mode allows a subgroup of group of a channels to be converted +in bursts of a given length. + +Injected conversions allow a second group of channels to be converted +separately from the regular group. An interrupt can be set to occur at the end +of conversion, which occurs after all channels have been scanned. + +@section adc_f4_api_ex Basic ADC Handling API. + +Example 1: Simple single channel conversion polled. Enable the peripheral clock +and ADC, reset ADC and set the prescaler divider. Set multiple mode to +independent. + +@code +gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1); +rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); +adc_set_clk_prescale(RCC_CFGR_ADCPRE_BY2); +adc_disable_scan_mode(ADC1); +adc_set_single_conversion_mode(ADC1); +adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC); +uint8_t channels[] = ADC_CHANNEL0; +adc_set_regular_sequence(ADC1, 1, channels); +adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT); +adc_power_on(ADC1); +adc_start_conversion_regular(ADC1); +while (! adc_eoc(ADC1)); +reg16 = adc_read_regular(ADC1); +@endcode + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for a Single Channel + +The sampling time can be selected in ADC clock cycles from 1.5 to 239.5. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref +adc_channel +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg + * NOTE Common with f1, f2 and f37x +*/ + +void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time) +{ + uint32_t reg32; + + if (channel < 10) { + reg32 = ADC_SMPR2(adc); + reg32 &= ~(0x7 << (channel * 3)); + reg32 |= (time << (channel * 3)); + ADC_SMPR2(adc) = reg32; + } else { + reg32 = ADC_SMPR1(adc); + reg32 &= ~(0x7 << ((channel - 10) * 3)); + reg32 |= (time << ((channel - 10) * 3)); + ADC_SMPR1(adc) = reg32; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for All Channels + +The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same +for all channels. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg + * NOTE Common with f1, f2 and f37x +*/ + +void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time) +{ + uint8_t i; + uint32_t reg32 = 0; + + for (i = 0; i <= 9; i++) { + reg32 |= (time << (i * 3)); + } + ADC_SMPR2(adc) = reg32; + + for (i = 10; i <= 17; i++) { + reg32 |= (time << ((i - 10) * 3)); + } + ADC_SMPR1(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + +If the ADC is in power-down mode then it is powered up. The application needs +to wait a time of about 3 microseconds for stabilization before using the ADC. +If the ADC is already on this function call will have no effect. + * NOTE Common with L1 and F2 + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_power_on(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_ADON; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Clock Prescale + +The ADC clock taken from the APB2 clock can be scaled down by 2, 4, 6 or 8. + +@param[in] prescale Unsigned int32. Prescale value for ADC Clock @ref +adc_ccr_adcpre +*/ + +void adc_set_clk_prescale(uint32_t prescale) +{ + uint32_t reg32 = ((ADC_CCR & ~ADC_CCR_ADCPRE_MASK) | prescale); + ADC_CCR = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Dual/Triple Mode + +The multiple mode uses ADC1 as master, ADC2 and optionally ADC3 in a slave +arrangement. This setting is applied to ADC1 only. + +The various modes possible are described in the reference manual. + +@param[in] mode Unsigned int32. Multiple mode selection from @ref adc_multi_mode +*/ + +void adc_set_multi_mode(uint32_t mode) +{ + ADC_CCR |= mode; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Regular Channels + +This enables an external trigger for set of defined regular channels, and sets +the polarity of the trigger event: rising or falling edge or both. Note that if +the trigger polarity is zero, triggering is disabled. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] trigger Unsigned int32. Trigger identifier @ref adc_trigger_regular +@param[in] polarity Unsigned int32. Trigger polarity @ref +adc_trigger_polarity_regular +*/ + +void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_CR2(adc); + + reg32 &= ~(ADC_CR2_EXTSEL_MASK | ADC_CR2_EXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_CR2(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Regular Channels + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_external_trigger_regular(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_EXTEN_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Injected Channels + +This enables an external trigger for set of defined injected channels, and sets +the polarity of the trigger event: rising or falling edge or both. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected +@param[in] polarity Unsigned int32. Trigger polarity @ref +adc_trigger_polarity_injected +*/ + +void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_CR2(adc); + + reg32 &= ~(ADC_CR2_JEXTSEL_MASK | ADC_CR2_JEXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_CR2(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Injected Channels + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_external_trigger_injected(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_JEXTEN_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set Resolution + +ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a +corresponding reduction in conversion time (resolution + 3 ADC clock cycles). + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] resolution Unsigned int32. Resolution value @ref adc_cr1_res +*/ + +void adc_set_resolution(uint32_t adc, uint32_t resolution) +{ + uint32_t reg32 = ADC_CR1(adc); + + reg32 &= ~ADC_CR1_RES_MASK; + reg32 |= resolution; + ADC_CR1(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable the Overrun Interrupt + +The overrun interrupt is generated when data is not read from a result register +before the next conversion is written. If DMA is enabled, all transfers are +terminated and any conversion sequence is aborted. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_overrun_interrupt(uint32_t adc) +{ + ADC_CR1(adc) |= ADC_CR1_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable the Overrun Interrupt + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_overrun_interrupt(uint32_t adc) +{ + ADC_CR1(adc) &= ~ADC_CR1_OVRIE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Overrun Flag + +The overrun flag is set when data is not read from a result register before the +next conversion is written. If DMA is enabled, all transfers are terminated and +any conversion sequence is aborted. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns Unsigned int32 conversion result. +*/ + +bool adc_get_overrun_flag(uint32_t adc) +{ + return ADC_SR(adc) & ADC_SR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Clear Overrun Flags + +The overrun flag is cleared. Note that if an overrun occurs, DMA is terminated. +The flag must be cleared and the DMA stream and ADC reinitialised to resume +conversions (see the reference manual). + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns Unsigned int32 conversion result. +*/ + +void adc_clear_overrun_flag(uint32_t adc) +{ +/* need to write zero to clear this */ + ADC_SR(adc) &= ~ADC_SR_OVR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an EOC for Each Conversion + +The EOC is set after each conversion in a sequence rather than at the end of the +sequence. Overrun detection is enabled only if DMA is enabled. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_eoc_after_each(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_EOCS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable the EOC for Each Conversion + +The EOC is set at the end of each sequence rather than after each conversion in +the sequence. Overrun detection is enabled always. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_eoc_after_group(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_EOCS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set DMA to Continue + +This must be set to allow DMA to continue to operate after the last conversion +in the DMA sequence. This allows DMA to be used in continuous circular mode. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_set_dma_continue(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_DDS; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Set DMA to Terminate + +This must be set to allow DMA to terminate after the last conversion in the DMA +sequence. This can avoid overrun errors. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_set_dma_terminate(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_DDS; +} +/*---------------------------------------------------------------------------*/ +/** @brief ADC Read the Analog Watchdog Flag + +This flag is set when the converted voltage crosses the high or low thresholds. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@returns bool. AWD flag. +*/ + +bool adc_awd(uint32_t adc) +{ + return ADC_SR(adc) & ADC_SR_AWD; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable The Temperature Sensor + +This enables both the sensor and the reference voltage measurements on channels +16 and 17. These are only available on ADC1 channel 16 and 17 respectively. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_enable_temperature_sensor() +{ + ADC_CCR |= ADC_CCR_TSVREFE; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Disable The Temperature Sensor + +Disabling this will reduce power consumption from the sensor and the reference +voltage measurements. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_temperature_sensor() +{ + ADC_CCR &= ~ADC_CCR_TSVREFE; +} + +/*---------------------------------------------------------------------------*/ + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f4/crc.c b/libopencm3/lib/stm32/f4/crc.c new file mode 100644 index 0000000..6bc9456 --- /dev/null +++ b/libopencm3/lib/stm32/f4/crc.c @@ -0,0 +1,33 @@ +/** @defgroup crc_file CRC + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx CRC + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/f4/crypto.c b/libopencm3/lib/stm32/f4/crypto.c new file mode 100644 index 0000000..651f365 --- /dev/null +++ b/libopencm3/lib/stm32/f4/crypto.c @@ -0,0 +1,66 @@ +/** @defgroup crypto_file CRYPTO + * + * @ingroup STM32F4xx + * + * @brief libopencm3 STM32F4xx CRYPTO + * + * @version 1.0.0 + * + * @date 18 Jun 2013 + * + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ + +/** @brief Set the MAC algorithm + */ +void crypto_set_mac_algorithm(enum crypto_mode_mac mode) +{ + crypto_set_algorithm((enum crypto_mode) mode); +} + +/** + * @brief Swap context + * + *@param[in] buf uint32_t Memory space for swap (16 items length) + */ +void crypto_context_swap(uint32_t *buf) +{ + int i; + /* Apply exact order of ? */ + for (i = 0; i < 8; i++) { + uint32_t save = *buf; + *buf++ = CRYP_CSGCMCCMR(i); + CRYP_CSGCMCCMR(i) = save; + }; + + for (i = 0; i < 8; i++) { + uint32_t save = *buf; + *buf++ = CRYP_CSGCMR(i); + CRYP_CSGCMCCMR(i) = save; + }; +} + +/**@}*/ diff --git a/libopencm3/lib/stm32/f4/dac.c b/libopencm3/lib/stm32/f4/dac.c new file mode 100644 index 0000000..c5397b6 --- /dev/null +++ b/libopencm3/lib/stm32/f4/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx DAC + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/dma.c b/libopencm3/lib/stm32/f4/dma.c new file mode 100644 index 0000000..6616621 --- /dev/null +++ b/libopencm3/lib/stm32/f4/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx DMA + +@version 1.0.0 + +@date 30 November 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/flash.c b/libopencm3/lib/stm32/f4/flash.c new file mode 100644 index 0000000..5353605 --- /dev/null +++ b/libopencm3/lib/stm32/f4/flash.c @@ -0,0 +1,53 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32F4xx + * + * @brief libopencm3 STM32F4xx FLASH + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * + * @date 14 January 2014 + * + * This library supports the FLASH memory controller in the STM32F4 + * series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * For the STM32F4xx, accessing FLASH memory is described briefly in + * section 2.3.3 of the STM32F4xx Reference Manual. + * For detailed programming information see: + * PM0081 programming manual: STM32F10xxx Flash programming + * September 2011, Doc ID 018520 Rev 1 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/**@}*/ + diff --git a/libopencm3/lib/stm32/f4/fmc.c b/libopencm3/lib/stm32/f4/fmc.c new file mode 100644 index 0000000..0de8a4a --- /dev/null +++ b/libopencm3/lib/stm32/f4/fmc.c @@ -0,0 +1,99 @@ +/* + * + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Utility functions for the SDRAM component of the FMC */ + +#include +#include + +/* + * Install various timing values into the correct place in the + * SDRAM Timing Control Register format. + * + * Note that the register is 'zero' based to save bits so 1 cycle + * is stored as '0'. This command takes actual cycles and adjusts + * by subtracting 1. + */ +uint32_t +sdram_timing(struct sdram_timing *t) { + uint32_t result; + + result = 0; + result |= ((t->trcd - 1) & 0xf) * FMC_SDTR_TRCD_SHIFT; + result |= ((t->trp - 1) & 0xf) * FMC_SDTR_TRP_SHIFT; + result |= ((t->twr - 1) & 0xf) * FMC_SDTR_TWR_SHIFT; + result |= ((t->trc - 1) & 0xf) * FMC_SDTR_TRC_SHIFT; + result |= ((t->tras - 1) & 0xf) * FMC_SDTR_TRAS_SHIFT; + result |= ((t->txsr - 1) & 0xf) * FMC_SDTR_TXSR_SHIFT; + result |= ((t->tmrd - 1) & 0xf) * FMC_SDTR_TMRD_SHIFT; + return result; +} + +/* + * Send a command to the SDRAM controller, wait until it is not + * busy before sending. This allows you to chain sending commands + * and the code will pause as needed between them. + */ +void +sdram_command(enum fmc_sdram_bank bank, + enum fmc_sdram_command cmd, int autorefresh, int modereg) { + uint32_t tmp_reg = 0; + + switch (bank) { + case SDRAM_BANK1: + tmp_reg = FMC_SDCMR_CTB1; + break; + case SDRAM_BANK2: + tmp_reg = FMC_SDCMR_CTB2; + break; + case SDRAM_BOTH_BANKS: + tmp_reg = FMC_SDCMR_CTB1 | FMC_SDCMR_CTB2; + break; + } + tmp_reg |= autorefresh * FMC_SDCMR_NRFS_SHIFT; + tmp_reg |= modereg * FMC_SDCMR_MRD_SHIFT; + switch (cmd) { + case SDRAM_CLK_CONF: + tmp_reg |= FMC_SDCMR_MODE_CLOCK_CONFIG_ENA; + break; + case SDRAM_AUTO_REFRESH: + tmp_reg |= FMC_SDCMR_MODE_AUTO_REFRESH; + break; + case SDRAM_LOAD_MODE: + tmp_reg |= FMC_SDCMR_MODE_LOAD_MODE_REGISTER; + break; + case SDRAM_PALL: + tmp_reg |= FMC_SDCMR_MODE_PALL; + break; + case SDRAM_SELF_REFRESH: + tmp_reg |= FMC_SDCMR_MODE_SELF_REFRESH; + break; + case SDRAM_POWER_DOWN: + tmp_reg |= FMC_SDCMR_MODE_POWER_DOWN; + break; + case SDRAM_NORMAL: + default: + break; + } + + /* Wait for the next chance to talk to the controller */ + while (FMC_SDSR & FMC_SDSR_BUSY) ; + + /* Send the next command */ + FMC_SDCMR = tmp_reg; +} diff --git a/libopencm3/lib/stm32/f4/gpio.c b/libopencm3/lib/stm32/f4/gpio.c new file mode 100644 index 0000000..ea59ae7 --- /dev/null +++ b/libopencm3/lib/stm32/f4/gpio.c @@ -0,0 +1,31 @@ +/** @defgroup gpio_file GPIO + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx General Purpose I/O + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/hash.c b/libopencm3/lib/stm32/f4/hash.c new file mode 100644 index 0000000..cd791bf --- /dev/null +++ b/libopencm3/lib/stm32/f4/hash.c @@ -0,0 +1,31 @@ +/** @defgroup hash_file HASH + * + * @ingroup STM32F4xx + * + * @brief libopencm3 STM32F4xx Hash Processor + * + * @version 1.0.0 + * + * @date 13 January 2014 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/i2c.c b/libopencm3/lib/stm32/f4/i2c.c new file mode 100644 index 0000000..67df9b1 --- /dev/null +++ b/libopencm3/lib/stm32/f4/i2c.c @@ -0,0 +1,31 @@ +/** @defgroup i2c_file I2C + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx I2C + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/iwdg.c b/libopencm3/lib/stm32/f4/iwdg.c new file mode 100644 index 0000000..3985657 --- /dev/null +++ b/libopencm3/lib/stm32/f4/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx Independent Watchdog Timer + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld b/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/f4/pwr.c b/libopencm3/lib/stm32/f4/pwr.c new file mode 100644 index 0000000..9b9e579 --- /dev/null +++ b/libopencm3/lib/stm32/f4/pwr.c @@ -0,0 +1,46 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32F4xx + * + * @brief libopencm3 STM32F4xx Power Control + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2011 Stephen Caudle + * + * @date 4 March 2013 + * + * This library supports the power control system for the + * STM32F4 series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +void pwr_set_vos_scale(vos_scale_t scale) +{ + if (scale == SCALE1) { + PWR_CR |= PWR_CR_VOS; + } else if (scale == SCALE2) { + PWR_CR &= PWR_CR_VOS; + } +} diff --git a/libopencm3/lib/stm32/f4/rcc.c b/libopencm3/lib/stm32/f4/rcc.c new file mode 100644 index 0000000..d862691 --- /dev/null +++ b/libopencm3/lib/stm32/f4/rcc.c @@ -0,0 +1,539 @@ +/** @defgroup rcc_file RCC + * + * @ingroup STM32F4xx + * + * @section rcc_f4_api_ex Reset and Clock Control API. + * + * @brief libopencm3 STM32F4xx Reset and Clock Control + * + * @author @htmlonly © @endhtmlonly 2013 Frantisek Burian + * + * @date 18 Jun 2013 + * + * This library supports the Reset and Clock Control System in the STM32 series + * of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include + +/**@{*/ + +/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */ +uint32_t rcc_ppre1_frequency = 16000000; +uint32_t rcc_ppre2_frequency = 16000000; + +const clock_scale_t hse_8mhz_3v3[CLOCK_3V3_END] = { + { /* 48MHz */ + .pllm = 8, + .plln = 96, + .pllp = 2, + .pllq = 2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 12000000, + .apb2_frequency = 24000000, + }, + { /* 120MHz */ + .pllm = 8, + .plln = 240, + .pllp = 2, + .pllq = 5, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 30000000, + .apb2_frequency = 60000000, + }, + { /* 168MHz */ + .pllm = 8, + .plln = 336, + .pllp = 2, + .pllq = 7, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_5WS, + .apb1_frequency = 42000000, + .apb2_frequency = 84000000, + }, +}; + +const clock_scale_t hse_12mhz_3v3[CLOCK_3V3_END] = { + { /* 48MHz */ + .pllm = 12, + .plln = 96, + .pllp = 2, + .pllq = 2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 12000000, + .apb2_frequency = 24000000, + }, + { /* 120MHz */ + .pllm = 12, + .plln = 240, + .pllp = 2, + .pllq = 5, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 30000000, + .apb2_frequency = 60000000, + }, + { /* 168MHz */ + .pllm = 12, + .plln = 336, + .pllp = 2, + .pllq = 7, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_5WS, + .apb1_frequency = 42000000, + .apb2_frequency = 84000000, + }, +}; + +const clock_scale_t hse_16mhz_3v3[CLOCK_3V3_END] = { + { /* 48MHz */ + .pllm = 16, + .plln = 96, + .pllp = 2, + .pllq = 2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 12000000, + .apb2_frequency = 24000000, + }, + { /* 120MHz */ + .pllm = 16, + .plln = 240, + .pllp = 2, + .pllq = 5, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 30000000, + .apb2_frequency = 60000000, + }, + { /* 168MHz */ + .pllm = 16, + .plln = 336, + .pllp = 2, + .pllq = 7, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_5WS, + .apb1_frequency = 42000000, + .apb2_frequency = 84000000, + }, +}; + +void rcc_osc_ready_int_clear(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +void rcc_osc_ready_int_enable(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +void rcc_osc_ready_int_disable(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + } +} + +int rcc_osc_ready_int_flag(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } + + cm3_assert_not_reached(); +} + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +void rcc_wait_for_osc_ready(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + +void rcc_wait_for_sysclk_status(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL); + break; + case HSE: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE); + break; + case HSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI); + break; + default: + /* Shouldn't be reached. */ + break; + } +} + +void rcc_osc_on(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +void rcc_osc_off(enum rcc_osc osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +void rcc_osc_bypass_enable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_osc_bypass_disable(enum rcc_osc osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + + + +void rcc_set_sysclk_source(uint32_t clk) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | clk); +} + +void rcc_set_pll_source(uint32_t pllsrc) +{ + uint32_t reg32; + + reg32 = RCC_PLLCFGR; + reg32 &= ~(1 << 22); + RCC_PLLCFGR = (reg32 | (pllsrc << 22)); +} + +void rcc_set_ppre2(uint32_t ppre2) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15)); + RCC_CFGR = (reg32 | (ppre2 << 13)); +} + +void rcc_set_ppre1(uint32_t ppre1) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12)); + RCC_CFGR = (reg32 | (ppre1 << 10)); +} + +void rcc_set_hpre(uint32_t hpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); + RCC_CFGR = (reg32 | (hpre << 4)); +} + +void rcc_set_rtcpre(uint32_t rtcpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); + RCC_CFGR = (reg32 | (rtcpre << 16)); +} + +void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq) +{ + RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | + (plln << RCC_PLLCFGR_PLLN_SHIFT) | + (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + (pllq << RCC_PLLCFGR_PLLQ_SHIFT); +} + +void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq) +{ + RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | + (plln << RCC_PLLCFGR_PLLN_SHIFT) | + (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + RCC_PLLCFGR_PLLSRC | + (pllq << RCC_PLLCFGR_PLLQ_SHIFT); +} + +uint32_t rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return (RCC_CFGR & 0x000c) >> 2; +} + +void rcc_clock_setup_hse_3v3(const clock_scale_t *clock) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_HSI); + + /* Enable external high-speed oscillator 8MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + + /* Enable/disable high performance mode */ + if (!clock->power_save) { + pwr_set_vos_scale(SCALE1); + } else { + pwr_set_vos_scale(SCALE2); + } + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre1(clock->ppre1); + rcc_set_ppre2(clock->ppre2); + + rcc_set_main_pll_hse(clock->pllm, clock->plln, + clock->pllp, clock->pllq); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_PLL); + + /* Wait for PLL clock to be selected. */ + rcc_wait_for_sysclk_status(PLL); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; + + /* Disable internal high-speed oscillator. */ + rcc_osc_off(HSI); +} + + + +/**@}*/ diff --git a/libopencm3/lib/stm32/f4/rtc.c b/libopencm3/lib/stm32/f4/rtc.c new file mode 100644 index 0000000..f08ac2b --- /dev/null +++ b/libopencm3/lib/stm32/f4/rtc.c @@ -0,0 +1,97 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32F4xx + * + * @brief libopencm3 STM32F4xx RTC + * + * @version 1.0.0 + * + * @date 4 March 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the wakeup timer + @warning You must unlock the registers before using this function + +*/ +void rtc_enable_wakeup_timer(void) +{ + RTC_CR |= RTC_CR_WUTE | (RTC_CR_OSEL_WAKEUP << RTC_CR_OSEL_SHIFT); + rtc_enable_wakeup_timer_interrupt(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the wakeup timer + @warning You must unlock the registers before using this function + +*/ +void rtc_disable_wakeup_timer(void) +{ + RTC_CR &= ~RTC_CR_WUTE; + rtc_disable_wakeup_timer_interrupt(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the wakeup timer interrupt + @warning You must unlock the registers before using this function + +*/ +void rtc_enable_wakeup_timer_interrupt(void) +{ + /* FTFM: + * To enable the RTC Wakeup interrupt, the following sequence is + * required: + * 1. Configure and enable the EXTI Line 22 in interrupt mode and + * select the rising edge sensitivity. + */ + exti_enable_request(EXTI22); + exti_set_trigger(EXTI22, EXTI_TRIGGER_RISING); + + /* 2. Configure and enable the RTC_WKUP IRQ channel in the NVIC. */ + nvic_enable_irq(NVIC_RTC_WKUP_IRQ); + nvic_set_priority(NVIC_RTC_WKUP_IRQ, 1); + + /* 3. Configure the RTC to generate the RTC wakeup timer event. */ + RTC_CR |= RTC_CR_WUTIE; /* Enable the interrupt */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the wakeup timer interrupt + @warning You must unlock the registers before using this function + +*/ +void rtc_disable_wakeup_timer_interrupt(void) +{ + /* 1. Disable EXTI Line 22 */ + exti_disable_request(EXTI22); + + /* 2. Disable RTC_WKUP IRQ channel in the NVIC. */ + nvic_disable_irq(NVIC_RTC_WKUP_IRQ); + + /* 3. Disable RTC wakeup timer event. */ + RTC_CR &= ~RTC_CR_WUTIE; +} diff --git a/libopencm3/lib/stm32/f4/spi.c b/libopencm3/lib/stm32/f4/spi.c new file mode 100644 index 0000000..c8a6b41 --- /dev/null +++ b/libopencm3/lib/stm32/f4/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx SPI + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/stm32f405x6.ld b/libopencm3/lib/stm32/f4/stm32f405x6.ld new file mode 100644 index 0000000..a8733f3 --- /dev/null +++ b/libopencm3/lib/stm32/f4/stm32f405x6.ld @@ -0,0 +1,33 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2011 Stephen Caudle + * Copyright (C) 2013 Sergey Krukowski + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for the STM32F405RGT6 chip (1024K flash, 128K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f4.ld + diff --git a/libopencm3/lib/stm32/f4/timer.c b/libopencm3/lib/stm32/f4/timer.c new file mode 100644 index 0000000..72ecd8d --- /dev/null +++ b/libopencm3/lib/stm32/f4/timer.c @@ -0,0 +1,38 @@ +/* This file is used for documentation purposes. It does not need +to be compiled. All source code is in the common area. +If there is any device specific code required it can be included here, +in which case this file must be added to the compile list. */ + +/** @defgroup timer_file Timers + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx Timers + +@version 1.0.0 + +@date 18 August 2012 + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/usart.c b/libopencm3/lib/stm32/f4/usart.c new file mode 100644 index 0000000..06254c9 --- /dev/null +++ b/libopencm3/lib/stm32/f4/usart.c @@ -0,0 +1,31 @@ +/** @defgroup usart_file USART + +@ingroup STM32F4xx + +@brief libopencm3 STM32F4xx USART + +@version 1.0.0 + +@date 30 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/f4/vector_chipset.c b/libopencm3/lib/stm32/f4/vector_chipset.c new file mode 100644 index 0000000..145be05 --- /dev/null +++ b/libopencm3/lib/stm32/f4/vector_chipset.c @@ -0,0 +1,27 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * Copyright (C) 2011 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +static void pre_main(void) +{ + /* Enable access to Floating-Point coprocessor. */ + SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11); +} diff --git a/libopencm3/lib/stm32/l1/Makefile b/libopencm3/lib/stm32/l1/Makefile new file mode 100644 index 0000000..00f4ba1 --- /dev/null +++ b/libopencm3/lib/stm32/l1/Makefile @@ -0,0 +1,52 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = libopencm3_stm32l1 +SRCLIBDIR ?= ../.. + +PREFIX ?= arm-none-eabi + +CC = $(PREFIX)-gcc +AR = $(PREFIX)-ar +CFLAGS = -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration \ + -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ + -Wundef -Wshadow \ + -I../../../include -fno-common \ + -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \ + -ffunction-sections -fdata-sections -MD -DSTM32L1 +# ARFLAGS = rcsv +ARFLAGS = rcs +OBJS = crc.o desig.o flash.o rcc.o usart.o dma.o lcd.o +OBJS += crc_common_all.o dac_common_all.o +OBJS += dma_common_l1f013.o +OBJS += gpio_common_all.o gpio_common_f0234.o +OBJS += i2c_common_all.o iwdg_common_all.o +OBJS += pwr_common_all.o pwr.o rtc_common_l1f024.o +OBJS += spi_common_all.o spi_common_l1f124.o timer_common_all.o +OBJS += usart_common_all.o usart_common_f124.o +OBJS += exti_common_all.o +OBJS += rcc_common_all.o +OBJS += usb.o usb_control.o usb_standard.o usb_f103.o +OBJS += adc.o adc_common_v1.o + +VPATH += ../../usb:../:../../cm3:../common + +include ../../Makefile.include + diff --git a/libopencm3/lib/stm32/l1/adc.c b/libopencm3/lib/stm32/l1/adc.c new file mode 100644 index 0000000..b3ca8a6 --- /dev/null +++ b/libopencm3/lib/stm32/l1/adc.c @@ -0,0 +1,201 @@ +/** @defgroup adc_file ADC + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx Analog to Digital Converters + +@author @htmlonly © @endhtmlonly 2014 Karl Palsson + + +LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +/**@{*/ + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Power On + +If the ADC is in power-down mode then it is powered up. The application needs +to wait a time of about 3 microseconds for stabilization before using the ADC. +If the ADC is already on this function call will have no effect. + * NOTE Common with F4 and F2 + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_power_on(uint32_t adc) +{ + ADC_CR2(adc) |= ADC_CR2_ADON; +} + + +/*----------------------------------------------------------------------------*/ + +/** @brief ADC Set the Sample Time for a Single Channel + +The sampling time can be selected in ADC clock cycles from 4 to 384. + +@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base. +@param[in] channel uint8. ADC Channel integer 0..18 or from @ref adc_channel. +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg. + */ +void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time) +{ + uint32_t reg32; + + if (channel < 10) { + reg32 = ADC_SMPR3(adc); + reg32 &= ~(0x7 << (channel * 3)); + reg32 |= (time << (channel * 3)); + ADC_SMPR3(adc) = reg32; + } else if (channel < 20) { + reg32 = ADC_SMPR2(adc); + reg32 &= ~(0x7 << ((channel - 10) * 3)); + reg32 |= (time << ((channel - 10) * 3)); + ADC_SMPR2(adc) = reg32; + } else { + reg32 = ADC_SMPR1(adc); + reg32 &= ~(0x7 << ((channel - 20) * 3)); + reg32 |= (time << ((channel - 20) * 3)); + ADC_SMPR1(adc) = reg32; + } +} + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Set the Sample Time for All Channels + +The sampling time can be selected in ADC clock cycles, same for +all channels. + +@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base. +@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg. +*/ + +void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time) +{ + uint8_t i; + uint32_t reg32 = 0; + + for (i = 0; i <= 9; i++) { + reg32 |= (time << (i * 3)); + } + ADC_SMPR0(adc) = reg32; + ADC_SMPR1(adc) = reg32; + ADC_SMPR2(adc) = reg32; + ADC_SMPR3(adc) = reg32; +} + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Enable The Temperature Sensor + +This enables both the sensor and the reference voltage measurements on channels +16 and 17. + +*/ +void adc_enable_temperature_sensor() +{ + ADC_CCR |= ADC_CCR_TSVREFE; +} + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Disable The Temperature Sensor + +Disabling this will reduce power consumption from the sensor and the reference +voltage measurements. + +*/ +void adc_disable_temperature_sensor() +{ + ADC_CCR &= ~ADC_CCR_TSVREFE; +} + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Regular Channels + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +*/ + +void adc_disable_external_trigger_regular(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_EXTEN_MASK; +} + +/*----------------------------------------------------------------------------*/ +/** @brief ADC Disable an External Trigger for Injected Channels + +@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base. +*/ + +void adc_disable_external_trigger_injected(uint32_t adc) +{ + ADC_CR2(adc) &= ~ADC_CR2_JEXTEN_MASK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Regular Channels + +This enables an external trigger for set of defined regular channels, and sets +the polarity of the trigger event: rising or falling edge or both. Note that if +the trigger polarity is zero, triggering is disabled. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] trigger Unsigned int32. Trigger identifier @ref adc_trigger_regular +@param[in] polarity Unsigned int32. Trigger polarity @ref +adc_trigger_polarity_regular +*/ + +void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_CR2(adc); + + reg32 &= ~(ADC_CR2_EXTSEL_MASK | ADC_CR2_EXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_CR2(adc) = reg32; +} + +/*---------------------------------------------------------------------------*/ +/** @brief ADC Enable an External Trigger for Injected Channels + +This enables an external trigger for set of defined injected channels, and sets +the polarity of the trigger event: rising or falling edge or both. + +@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base +@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected +@param[in] polarity Unsigned int32. Trigger polarity @ref +adc_trigger_polarity_injected +*/ + +void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger, + uint32_t polarity) +{ + uint32_t reg32 = ADC_CR2(adc); + + reg32 &= ~(ADC_CR2_JEXTSEL_MASK | ADC_CR2_JEXTEN_MASK); + reg32 |= (trigger | polarity); + ADC_CR2(adc) = reg32; +} + +/**@}*/ + + diff --git a/libopencm3/lib/stm32/l1/crc.c b/libopencm3/lib/stm32/l1/crc.c new file mode 100644 index 0000000..8a71c89 --- /dev/null +++ b/libopencm3/lib/stm32/l1/crc.c @@ -0,0 +1,33 @@ +/** @defgroup crc_file CRC + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx CRC + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + + diff --git a/libopencm3/lib/stm32/l1/dac.c b/libopencm3/lib/stm32/l1/dac.c new file mode 100644 index 0000000..ed118b4 --- /dev/null +++ b/libopencm3/lib/stm32/l1/dac.c @@ -0,0 +1,31 @@ +/** @defgroup dac_file DAC + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx DAC + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/dma.c b/libopencm3/lib/stm32/l1/dma.c new file mode 100644 index 0000000..6f4622d --- /dev/null +++ b/libopencm3/lib/stm32/l1/dma.c @@ -0,0 +1,31 @@ +/** @defgroup dma_file DMA + * + * @ingroup STM32L1xx + * + * @brief libopencm3 STM32L1xx DMA + * + * @version 1.0.0 + * + * @date 10 July 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/flash.c b/libopencm3/lib/stm32/l1/flash.c new file mode 100644 index 0000000..fdd2cca --- /dev/null +++ b/libopencm3/lib/stm32/l1/flash.c @@ -0,0 +1,208 @@ +/** @defgroup flash_file FLASH + * + * @ingroup STM32L1xx + * + * @brief libopencm3 STM32L1xx FLASH + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * @author @htmlonly © @endhtmlonly 2012 + * Karl Palsson + * + * @date 14 January 2014 + * + * For the STM32L1xx, accessing FLASH memory is described briefly in + * section 2.3.3 of the STM32L1xx Reference Manual. + * For detailed programming information see: + * PM0062 programming manual: STM32L1xxxx Flash and EEPROM programming + * March 2012, Doc ID 16024 Rev 5 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * Copyright (C) 2012-13 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Enable 64 Bit Programming Mode + +*/ + +void flash_64bit_enable(void) +{ + FLASH_ACR |= FLASH_ACR_ACC64; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable 32 Bit Programming Mode + +This mode is a low power mode. It must be used at low frequencies and does not +allow prefetch or wait states to be used. +*/ + +void flash_64bit_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_ACC64; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the FLASH Prefetch Buffer + +This buffer is used for instruction fetches and is enabled by default after +reset. + +Note carefully the restrictions under which the prefetch buffer may be +enabled or disabled. Prefetch is only available when 64-bit +access is enabled. +*/ + +void flash_prefetch_enable(void) +{ + FLASH_ACR |= FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the FLASH Prefetch Buffer + +Note carefully the restrictions under which the prefetch buffer may be +set to disabled. See the reference and programming manuals for details. +*/ + +void flash_prefetch_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Number of Wait States + +Used to match the system clock to the FLASH memory access time. See the +programming manual for more information on clock speed and voltage ranges. The +latency must be changed to the appropriate value before any increase in +clock speed, or after any decrease in clock speed. A latency setting of +zero only applies if 64-bit mode is not used. + +@param[in] uint32_t ws: values from @ref flash_latency. +*/ + +void flash_set_ws(uint32_t ws) +{ + uint32_t reg32; + + reg32 = FLASH_ACR; + reg32 &= ~(1 << 0); + reg32 |= ws; + FLASH_ACR = reg32; +} + +void flash_unlock_pecr(void) { + FLASH_PEKEYR = FLASH_PEKEYR_PEKEY1; + FLASH_PEKEYR = FLASH_PEKEYR_PEKEY2; +} + +void flash_lock_pecr(void) { + FLASH_PECR |= FLASH_PECR_PELOCK; +} + +void flash_unlock_progmem(void) { + flash_unlock_pecr(); + FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY1; + FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY2; +} + +void flash_lock_progmem(void) { + FLASH_PECR |= FLASH_PECR_PRGLOCK; +} + +void flash_unlock_option_bytes(void) { + flash_unlock_pecr(); + FLASH_OPTKEYR = FLASH_OPTKEYR_OPTKEY1; + FLASH_OPTKEYR = FLASH_OPTKEYR_OPTKEY2; +} + +void flash_lock_option_bytes(void) { + FLASH_PECR |= FLASH_PECR_OPTLOCK; +} + +/** @brief Unlock all segments of flash + * + */ +void flash_unlock(void) { + flash_unlock_pecr(); + flash_unlock_progmem(); + flash_unlock_option_bytes(); +} + +/** @brief Lock all segments of flash + * + */ +void flash_lock(void) { + flash_lock_option_bytes(); + flash_lock_progmem(); + flash_lock_pecr(); +} + +/** @brief Write a word to eeprom + * + * @param address assumed to be in the eeprom space, no checking + * @param data word to write + */ +void eeprom_program_word(uint32_t address, uint32_t data) { + flash_unlock_pecr(); + /* erase only if needed */ + FLASH_PECR &= ~FLASH_PECR_FTDW; + MMIO32(address) = data; + flash_lock_pecr(); +} + +/** @brief Write a block of words to eeprom + * + * Writes a block of words to EEPROM at the requested address, erasing if necessary, + * and locking afterwards. Only wordwise writing is safe for writing any value + * + * @param[in] address must point to EEPROM space, no checking! + * @param[in] data pointer to data to write + * @param[in] length size of of data in WORDS! + * */ +void eeprom_program_words(uint32_t address, uint32_t *data, int length_in_words) +{ + int i; + flash_unlock_pecr(); + while (FLASH_SR & FLASH_SR_BSY); + /* erase only if needed */ + FLASH_PECR &= ~FLASH_PECR_FTDW; + for (i = 0; i < length_in_words; i++) { + MMIO32(address + (i * sizeof(uint32_t))) = *(data+i); + while (FLASH_SR & FLASH_SR_BSY); + } + flash_lock_pecr(); +} + + +/**@}*/ diff --git a/libopencm3/lib/stm32/l1/gpio.c b/libopencm3/lib/stm32/l1/gpio.c new file mode 100644 index 0000000..46ea658 --- /dev/null +++ b/libopencm3/lib/stm32/l1/gpio.c @@ -0,0 +1,31 @@ +/** @defgroup gpio_file GPIO + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx General Purpose I/O + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/i2c.c b/libopencm3/lib/stm32/l1/i2c.c new file mode 100644 index 0000000..2390c96 --- /dev/null +++ b/libopencm3/lib/stm32/l1/i2c.c @@ -0,0 +1,31 @@ +/** @defgroup i2c_file I2C + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx I2C + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/iwdg.c b/libopencm3/lib/stm32/l1/iwdg.c new file mode 100644 index 0000000..1f37fe8 --- /dev/null +++ b/libopencm3/lib/stm32/l1/iwdg.c @@ -0,0 +1,31 @@ +/** @defgroup iwdg_file IWDG + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx Independent Watchdog Timer + +@version 1.0.0 + +@date 18 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/lcd.c b/libopencm3/lib/stm32/l1/lcd.c new file mode 100644 index 0000000..68173ab --- /dev/null +++ b/libopencm3/lib/stm32/l1/lcd.c @@ -0,0 +1,154 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Nikolay Merinov + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +void lcd_enable(void) +{ + LCD_CR |= LCD_CR_LCDEN; +} + +void lcd_update(void) +{ + LCD_SR |= LCD_SR_UDR; +} + +void lcd_wait_for_lcd_enabled(void) +{ + while ((LCD_SR & LCD_SR_ENS) == 0); +} + +void lcd_wait_for_step_up_ready(void) +{ + while ((LCD_SR & LCD_SR_RDY) == 0); +} + +void lcd_wait_for_update_ready(void) +{ + while ((LCD_SR & LCD_SR_UDR) != 0); +} + +int lcd_is_enabled(void) +{ + return ((LCD_SR & LCD_SR_ENS) != 0); +} + +int lcd_is_step_up_ready(void) +{ + return ((LCD_SR & LCD_SR_RDY) != 0); +} + +int lcd_is_for_update_ready(void) +{ + return ((LCD_SR & LCD_SR_UDR) == 0); +} + +void lcd_set_contrast(uint8_t contrast) +{ + LCD_FCR &= ~(LCD_FCR_CC_MASK << LCD_FCR_CC_SHIFT); + LCD_FCR |= contrast << LCD_FCR_CC_SHIFT; +} + +void lcd_set_bias(uint8_t bias) +{ + LCD_CR &= ~(LCD_CR_BIAS_MASK << LCD_CR_BIAS_SHIFT); + LCD_CR |= bias << LCD_CR_BIAS_SHIFT; +} + +void lcd_set_duty(uint8_t duty) +{ + LCD_CR &= ~(LCD_CR_DUTY_MASK << LCD_CR_DUTY_SHIFT); + LCD_CR |= duty << LCD_CR_DUTY_SHIFT; +} + +void lcd_set_prescaler(uint8_t ps) +{ + LCD_FCR &= ~(LCD_FCR_PS_MASK << LCD_FCR_PS_SHIFT); + LCD_FCR |= ps << LCD_FCR_PS_SHIFT; +} + +void lcd_set_divider(uint8_t div) +{ + LCD_FCR &= ~(LCD_FCR_DIV_MASK << LCD_FCR_DIV_SHIFT); + LCD_FCR |= div << LCD_FCR_DIV_SHIFT; +} + +void lcd_enable_segment_multiplexing(void) +{ + LCD_CR |= LCD_CR_MUX_SEG; +} + +void lcd_disable_segment_multiplexing(void) +{ + LCD_CR &= ~LCD_CR_MUX_SEG; +} + +void lcd_set_refresh_frequency(uint32_t frequency) +{ + uint32_t duty, lcd_clock; + switch ((LCD_CR >> LCD_CR_DUTY_SHIFT) & LCD_CR_DUTY_MASK) { + case LCD_CR_DUTY_STATIC: + duty = 1; + break; + case LCD_CR_DUTY_1_2: + duty = 2; + break; + case LCD_CR_DUTY_1_3: + duty = 3; + break; + case LCD_CR_DUTY_1_4: + duty = 4; + break; + case LCD_CR_DUTY_1_8: + duty = 8; + break; + default: + /* Incorrect duty */ + return; + } + + switch ((RCC_CSR >> RCC_CSR_RTCSEL_SHIFT) & RCC_CSR_RTCSEL_MASK) { + case RCC_CSR_RTCSEL_LSE: + lcd_clock = 32786; + break; + case RCC_CSR_RTCSEL_LSI: + lcd_clock = 37000; + break; + case RCC_CSR_RTCSEL_HSI: + lcd_clock = 16000000; + break; + default: + /* RCC Clock not selected */ + return; + } + + /* PS * DIV = lcd_clock/(duty * freq) */ + uint32_t ps_mul_div = lcd_clock / (duty * frequency); + + int div, ps = 0; + while (ps_mul_div > 32) { + ps_mul_div >>= 1; + ps++; + } + div = ps_mul_div - 16; + + lcd_set_prescaler(ps); + lcd_set_divider(div); +} diff --git a/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld b/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld new file mode 100644 index 0000000..3fc2ccb --- /dev/null +++ b/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld @@ -0,0 +1,106 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Generic linker script for STM32 targets using libopencm3. */ + +/* Memory regions must be defined in the ld script which includes this one. */ + +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/libopencm3/lib/stm32/l1/pwr.c b/libopencm3/lib/stm32/l1/pwr.c new file mode 100644 index 0000000..64210d5 --- /dev/null +++ b/libopencm3/lib/stm32/l1/pwr.c @@ -0,0 +1,58 @@ +/** @defgroup pwr_file PWR + * + * @ingroup STM32L1xx + * + * @brief libopencm3 STM32L1xx Power Control + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2012 Karl Palsson + * + * @date 4 March 2013 + * + * This library supports the power control system for the + * STM32L1 series of ARM Cortex Microcontrollers by ST Microelectronics. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +void pwr_set_vos_scale(vos_scale_t scale) +{ + /* You are not allowed to write zeros here, don't try and optimize! */ + uint32_t reg = PWR_CR; + reg &= ~(PWR_CR_VOS_MASK); + switch (scale) { + case RANGE1: + reg |= PWR_CR_VOS_RANGE1; + break; + case RANGE2: + reg |= PWR_CR_VOS_RANGE2; + break; + case RANGE3: + reg |= PWR_CR_VOS_RANGE3; + break; + } + PWR_CR = reg; +} + diff --git a/libopencm3/lib/stm32/l1/rcc.c b/libopencm3/lib/stm32/l1/rcc.c new file mode 100644 index 0000000..4efd789 --- /dev/null +++ b/libopencm3/lib/stm32/l1/rcc.c @@ -0,0 +1,534 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * Based on the F4 code... + */ + +#include +#include +#include + +/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */ +uint32_t rcc_ppre1_frequency = 2097000; +uint32_t rcc_ppre2_frequency = 2097000; + +const clock_scale_t clock_config[CLOCK_CONFIG_END] = { + { /* 24MHz PLL from HSI */ + .pll_source = RCC_CFGR_PLLSRC_HSI_CLK, + .pll_mul = RCC_CFGR_PLLMUL_MUL3, + .pll_div = RCC_CFGR_PLLDIV_DIV2, + .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_1WS, + .apb1_frequency = 24000000, + .apb2_frequency = 24000000, + }, + { /* 32MHz PLL from HSI */ + .pll_source = RCC_CFGR_PLLSRC_HSI_CLK, + .pll_mul = RCC_CFGR_PLLMUL_MUL6, + .pll_div = RCC_CFGR_PLLDIV_DIV3, + .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_1WS, + .apb1_frequency = 32000000, + .apb2_frequency = 32000000, + }, + { /* 16MHz HSI raw */ + .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_0WS, + .apb1_frequency = 16000000, + .apb2_frequency = 16000000, + }, + { /* 4MHz HSI raw */ + .hpre = RCC_CFGR_HPRE_SYSCLK_DIV4, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_0WS, + .apb1_frequency = 4000000, + .apb2_frequency = 4000000, + }, + { /* 4MHz MSI raw */ + .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_0WS, + .apb1_frequency = 4194000, + .apb2_frequency = 4194000, + .msi_range = RCC_ICSCR_MSIRANGE_4MHZ, + }, + { /* 2MHz MSI raw */ + .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV, + .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, + .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, + .voltage_scale = RANGE1, + .flash_config = FLASH_ACR_LATENCY_0WS, + .apb1_frequency = 2097000, + .apb2_frequency = 2097000, + .msi_range = RCC_ICSCR_MSIRANGE_2MHZ, + }, +}; + +void rcc_osc_ready_int_clear(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + case MSI: + RCC_CIR |= RCC_CIR_MSIRDYC; + break; + } +} + +void rcc_osc_ready_int_enable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + case MSI: + RCC_CIR |= RCC_CIR_MSIRDYIE; + break; + } +} + +void rcc_osc_ready_int_disable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + case MSI: + RCC_CIR &= ~RCC_CIR_MSIRDYIE; + break; + } +} + +int rcc_osc_ready_int_flag(osc_t osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + case MSI: + return ((RCC_CIR & RCC_CIR_MSIRDYF) != 0); + break; + } + + /* Shouldn't be reached. */ + return -1; +} + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +void rcc_wait_for_osc_ready(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case MSI: + while ((RCC_CR & RCC_CR_MSIRDY) == 0); + break; + case LSE: + while ((RCC_CSR & RCC_CSR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + +void rcc_wait_for_sysclk_status(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != + RCC_CFGR_SWS_SYSCLKSEL_PLLCLK); + break; + case HSE: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != + RCC_CFGR_SWS_SYSCLKSEL_HSECLK); + break; + case HSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != + RCC_CFGR_SWS_SYSCLKSEL_HSICLK); + break; + case MSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != + RCC_CFGR_SWS_SYSCLKSEL_MSICLK); + break; + default: + /* Shouldn't be reached. */ + break; + } +} + +void rcc_osc_on(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case MSI: + RCC_CR |= RCC_CR_MSION; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_CSR |= RCC_CSR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +void rcc_osc_off(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case MSI: + RCC_CR &= ~RCC_CR_MSION; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_CSR &= ~RCC_CSR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +void rcc_osc_bypass_enable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_CSR |= RCC_CSR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + case MSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_osc_bypass_disable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_CSR &= ~RCC_CSR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + case MSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_set_sysclk_source(uint32_t clk) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | clk); +} + +void rcc_set_pll_configuration(uint32_t source, uint32_t multiplier, + uint32_t divisor) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~(RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT); + reg32 &= ~(RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT); + reg32 &= ~(1 << 16); + reg32 |= (source << 16); + reg32 |= (multiplier << RCC_CFGR_PLLMUL_SHIFT); + reg32 |= (divisor << RCC_CFGR_PLLDIV_SHIFT); + RCC_CFGR = reg32; +} + +void rcc_set_pll_source(uint32_t pllsrc) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~(1 << 16); + RCC_CFGR = (reg32 | (pllsrc << 16)); +} + +void rcc_set_ppre2(uint32_t ppre2) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 13) | (1 << 12) | (1 << 11)); + RCC_CFGR = (reg32 | (ppre2 << 11)); +} + +void rcc_set_ppre1(uint32_t ppre1) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 10) | (1 << 9) | (1 << 8)); + RCC_CFGR = (reg32 | (ppre1 << 8)); +} + +void rcc_set_hpre(uint32_t hpre) +{ + uint32_t reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); + RCC_CFGR = (reg32 | (hpre << 4)); +} + +void rcc_set_rtcpre(uint32_t rtcpre) +{ + uint32_t reg32; + + reg32 = RCC_CR; + reg32 &= ~((1 << 30) | (1 << 29)); + RCC_CR = (reg32 | (rtcpre << 29)); +} + +uint32_t rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return (RCC_CFGR & 0x000c) >> 2; +} + +void rcc_rtc_select_clock(uint32_t clock) +{ + RCC_CSR &= ~(RCC_CSR_RTCSEL_MASK << RCC_CSR_RTCSEL_SHIFT); + RCC_CSR |= (clock << RCC_CSR_RTCSEL_SHIFT); +} + +void rcc_clock_setup_msi(const clock_scale_t *clock) +{ + /* Enable internal multi-speed oscillator. */ + + uint32_t reg = RCC_ICSCR; + reg &= ~(RCC_ICSCR_MSIRANGE_MASK << RCC_ICSCR_MSIRANGE_SHIFT); + reg |= (clock->msi_range << RCC_ICSCR_MSIRANGE_SHIFT); + RCC_ICSCR = reg; + + rcc_osc_on(MSI); + rcc_wait_for_osc_ready(MSI); + + /* Select MSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_MSICLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre1(clock->ppre1); + rcc_set_ppre2(clock->ppre2); + + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN); + pwr_set_vos_scale(clock->voltage_scale); + + /* I guess this should be in the settings? */ + flash_64bit_enable(); + flash_prefetch_enable(); + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; +} + +void rcc_clock_setup_hsi(const clock_scale_t *clock) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre1(clock->ppre1); + rcc_set_ppre2(clock->ppre2); + + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN); + pwr_set_vos_scale(clock->voltage_scale); + + /* I guess this should be in the settings? */ + flash_64bit_enable(); + flash_prefetch_enable(); + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; +} + +void rcc_clock_setup_pll(const clock_scale_t *clock) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(clock->hpre); + rcc_set_ppre1(clock->ppre1); + rcc_set_ppre2(clock->ppre2); + + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN); + pwr_set_vos_scale(clock->voltage_scale); + + /* I guess this should be in the settings? */ + flash_64bit_enable(); + flash_prefetch_enable(); + /* Configure flash settings. */ + flash_set_ws(clock->flash_config); + + rcc_set_pll_configuration(clock->pll_source, clock->pll_mul, + clock->pll_div); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used. */ + rcc_ppre1_frequency = clock->apb1_frequency; + rcc_ppre2_frequency = clock->apb2_frequency; +} diff --git a/libopencm3/lib/stm32/l1/rtc.c b/libopencm3/lib/stm32/l1/rtc.c new file mode 100644 index 0000000..5628aa7 --- /dev/null +++ b/libopencm3/lib/stm32/l1/rtc.c @@ -0,0 +1,31 @@ +/** @defgroup rtc_file RTC + * + * @ingroup STM32L1xx + * + * @brief libopencm3 STM32L1xx RTC + * + * @version 1.0.0 + * + * @date 4 March 2013 + * + * LGPL License Terms @ref lgpl_license + */ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/spi.c b/libopencm3/lib/stm32/l1/spi.c new file mode 100644 index 0000000..05969fb --- /dev/null +++ b/libopencm3/lib/stm32/l1/spi.c @@ -0,0 +1,31 @@ +/** @defgroup spi_file SPI + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx SPI + +@version 1.0.0 + +@date 15 October 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/stm32/l1/stm32l15xx6.ld b/libopencm3/lib/stm32/l1/stm32l15xx6.ld new file mode 100644 index 0000000..a72a5d8 --- /dev/null +++ b/libopencm3/lib/stm32/l1/stm32l15xx6.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32L15xx6, 32K flash, 10K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K + eep (r) : ORIGIN = 0x08080000, LENGTH = 4K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32l1.ld + diff --git a/libopencm3/lib/stm32/l1/stm32l15xx8.ld b/libopencm3/lib/stm32/l1/stm32l15xx8.ld new file mode 100644 index 0000000..656779b --- /dev/null +++ b/libopencm3/lib/stm32/l1/stm32l15xx8.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32L15xx8, 64K flash, 10K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K + eep (r) : ORIGIN = 0x08080000, LENGTH = 4K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32l1.ld + diff --git a/libopencm3/lib/stm32/l1/stm32l15xxb.ld b/libopencm3/lib/stm32/l1/stm32l15xxb.ld new file mode 100644 index 0000000..be81f37 --- /dev/null +++ b/libopencm3/lib/stm32/l1/stm32l15xxb.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32L15xxB, 128K flash, 16K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K + eep (r) : ORIGIN = 0x08080000, LENGTH = 4K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32l1.ld + diff --git a/libopencm3/lib/stm32/l1/stm32l15xxc.ld b/libopencm3/lib/stm32/l1/stm32l15xxc.ld new file mode 100644 index 0000000..651aed3 --- /dev/null +++ b/libopencm3/lib/stm32/l1/stm32l15xxc.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32L15xxC, 256k flash, 32K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K + eep (r) : ORIGIN = 0x08080000, LENGTH = 8K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32l1.ld + diff --git a/libopencm3/lib/stm32/l1/stm32l15xxd.ld b/libopencm3/lib/stm32/l1/stm32l15xxd.ld new file mode 100644 index 0000000..4b93c9b --- /dev/null +++ b/libopencm3/lib/stm32/l1/stm32l15xxd.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32L15xxD, 384K flash, 38K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K + eep (r) : ORIGIN = 0x08080000, LENGTH = 12K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32l1.ld + diff --git a/libopencm3/lib/stm32/l1/timer.c b/libopencm3/lib/stm32/l1/timer.c new file mode 100644 index 0000000..ab69c62 --- /dev/null +++ b/libopencm3/lib/stm32/l1/timer.c @@ -0,0 +1,59 @@ +/** @defgroup timer_file Timers + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx Timers + +@version 1.0.0 + +@date 18 August 2012 + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Edward Cheeseman + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set Timer Option + +Set timer options register on TIM2 or TIM3, used for trigger remapping. + +@param[in] timer_peripheral Unsigned int32. Timer register address base +@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM3: +@ref tim3_opt_trigger_remap. +*/ + +void timer_set_option(uint32_t timer_peripheral, uint32_t option) +{ + if (timer_peripheral == TIM2) { + TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK; + TIM_OR(timer_peripheral) |= option; + } else if (timer_peripheral == TIM3) { + TIM_OR(timer_peripheral) &= ~TIM3_OR_ITR2_RMP_MASK; + TIM_OR(timer_peripheral) |= option; + } +} + +/**@}*/ + diff --git a/libopencm3/lib/stm32/l1/usart.c b/libopencm3/lib/stm32/l1/usart.c new file mode 100644 index 0000000..5e357bf --- /dev/null +++ b/libopencm3/lib/stm32/l1/usart.c @@ -0,0 +1,31 @@ +/** @defgroup usart_file USART + +@ingroup STM32L1xx + +@brief libopencm3 STM32L1xx USART + +@version 1.0.0 + +@date 30 August 2012 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include diff --git a/libopencm3/lib/usb/usb.c b/libopencm3/lib/usb/usb.c new file mode 100644 index 0000000..7863736 --- /dev/null +++ b/libopencm3/lib/usb/usb.c @@ -0,0 +1,175 @@ +/** @defgroup usb_drivers_file Generic USB Drivers + +@ingroup USB + +@brief Generic USB Drivers + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include "usb_private.h" + +/** + * Main initialization entry point. + * + * Initialize the USB firmware library to implement the USB device described + * by the descriptors provided. + * + * It is required that the 48MHz USB clock is already available. + * + * @param driver TODO + * @param dev Pointer to USB device descriptor. This must not be changed while + * the device is in use. + * @param conf Pointer to array of USB configuration descriptors. These must + * not be changed while the device is in use. The length of this + * array is determined by the bNumConfigurations field in the + * device descriptor. + * @param strings TODO + * @param control_buffer Pointer to array that would hold the data + * received during control requests with DATA + * stage + * @param control_buffer_size Size of control_buffer + * @return Zero on success (currently cannot fail). + */ +usbd_device *usbd_init(const usbd_driver *driver, + const struct usb_device_descriptor *dev, + const struct usb_config_descriptor *conf, + const char **strings, int num_strings, + uint8_t *control_buffer, uint16_t control_buffer_size) +{ + usbd_device *usbd_dev; + + usbd_dev = driver->init(); + + usbd_dev->driver = driver; + usbd_dev->desc = dev; + usbd_dev->config = conf; + usbd_dev->strings = strings; + usbd_dev->num_strings = num_strings; + usbd_dev->ctrl_buf = control_buffer; + usbd_dev->ctrl_buf_len = control_buffer_size; + + usbd_dev->user_callback_ctr[0][USB_TRANSACTION_SETUP] = + _usbd_control_setup; + usbd_dev->user_callback_ctr[0][USB_TRANSACTION_OUT] = + _usbd_control_out; + usbd_dev->user_callback_ctr[0][USB_TRANSACTION_IN] = + _usbd_control_in; + + return usbd_dev; +} + +void usbd_register_reset_callback(usbd_device *usbd_dev, void (*callback)(void)) +{ + usbd_dev->user_callback_reset = callback; +} + +void usbd_register_suspend_callback(usbd_device *usbd_dev, + void (*callback)(void)) +{ + usbd_dev->user_callback_suspend = callback; +} + +void usbd_register_resume_callback(usbd_device *usbd_dev, + void (*callback)(void)) +{ + usbd_dev->user_callback_resume = callback; +} + +void usbd_register_sof_callback(usbd_device *usbd_dev, void (*callback)(void)) +{ + usbd_dev->user_callback_sof = callback; +} + +void _usbd_reset(usbd_device *usbd_dev) +{ + usbd_dev->current_address = 0; + usbd_dev->current_config = 0; + usbd_ep_setup(usbd_dev, 0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL); + usbd_dev->driver->set_address(usbd_dev, 0); + + if (usbd_dev->user_callback_reset) { + usbd_dev->user_callback_reset(); + } +} + +/* Functions to wrap the low-level driver */ +void usbd_poll(usbd_device *usbd_dev) +{ + usbd_dev->driver->poll(usbd_dev); +} + +void usbd_disconnect(usbd_device *usbd_dev, bool disconnected) +{ + /* not all drivers support disconnection */ + if (usbd_dev->driver->disconnect) { + usbd_dev->driver->disconnect(usbd_dev, disconnected); + } +} + +void usbd_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*callback)(usbd_device *usbd_dev, uint8_t ep)) +{ + usbd_dev->driver->ep_setup(usbd_dev, addr, type, max_size, callback); +} + +uint16_t usbd_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len) +{ + return usbd_dev->driver->ep_write_packet(usbd_dev, addr, buf, len); +} + +uint16_t usbd_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf, + uint16_t len) +{ + return usbd_dev->driver->ep_read_packet(usbd_dev, addr, buf, len); +} + +void usbd_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall) +{ + usbd_dev->driver->ep_stall_set(usbd_dev, addr, stall); +} + +uint8_t usbd_ep_stall_get(usbd_device *usbd_dev, uint8_t addr) +{ + return usbd_dev->driver->ep_stall_get(usbd_dev, addr); +} + +void usbd_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak) +{ + usbd_dev->driver->ep_nak_set(usbd_dev, addr, nak); +} + +/**@}*/ + diff --git a/libopencm3/lib/usb/usb_control.c b/libopencm3/lib/usb/usb_control.c new file mode 100644 index 0000000..1b87057 --- /dev/null +++ b/libopencm3/lib/usb/usb_control.c @@ -0,0 +1,288 @@ +/** @defgroup usb_control_file Generic USB Control Requests + +@ingroup USB + +@brief Generic USB Control Requests + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include "usb_private.h" + +/* + * According to the USB 2.0 specification, section 8.5.3, when a control + * transfer is stalled, the pipe becomes idle. We provide one utility to stall + * a transaction to reduce boilerplate code. + */ +static void stall_transaction(usbd_device *usbd_dev) +{ + usbd_ep_stall_set(usbd_dev, 0, 1); + usbd_dev->control_state.state = IDLE; +} + +/* Register application callback function for handling USB control requests. */ +int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type, + uint8_t type_mask, + usbd_control_callback callback) +{ + int i; + + for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + if (usbd_dev->user_control_callback[i].cb) { + continue; + } + + usbd_dev->user_control_callback[i].type = type; + usbd_dev->user_control_callback[i].type_mask = type_mask; + usbd_dev->user_control_callback[i].cb = callback; + return 0; + } + + return -1; +} + +static void usb_control_send_chunk(usbd_device *usbd_dev) +{ + if (usbd_dev->desc->bMaxPacketSize0 < + usbd_dev->control_state.ctrl_len) { + /* Data stage, normal transmission */ + usbd_ep_write_packet(usbd_dev, 0, + usbd_dev->control_state.ctrl_buf, + usbd_dev->desc->bMaxPacketSize0); + usbd_dev->control_state.state = DATA_IN; + usbd_dev->control_state.ctrl_buf += + usbd_dev->desc->bMaxPacketSize0; + usbd_dev->control_state.ctrl_len -= + usbd_dev->desc->bMaxPacketSize0; + } else { + /* Data stage, end of transmission */ + usbd_ep_write_packet(usbd_dev, 0, + usbd_dev->control_state.ctrl_buf, + usbd_dev->control_state.ctrl_len); + usbd_dev->control_state.state = LAST_DATA_IN; + usbd_dev->control_state.ctrl_len = 0; + usbd_dev->control_state.ctrl_buf = NULL; + } +} + +static int usb_control_recv_chunk(usbd_device *usbd_dev) +{ + uint16_t packetsize = MIN(usbd_dev->desc->bMaxPacketSize0, + usbd_dev->control_state.req.wLength - + usbd_dev->control_state.ctrl_len); + uint16_t size = usbd_ep_read_packet(usbd_dev, 0, + usbd_dev->control_state.ctrl_buf + + usbd_dev->control_state.ctrl_len, + packetsize); + + if (size != packetsize) { + stall_transaction(usbd_dev); + return -1; + } + + usbd_dev->control_state.ctrl_len += size; + + return packetsize; +} + +static int usb_control_request_dispatch(usbd_device *usbd_dev, + struct usb_setup_data *req) +{ + int i, result = 0; + struct user_control_callback *cb = usbd_dev->user_control_callback; + + /* Call user command hook function. */ + for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + if (cb[i].cb == NULL) { + break; + } + + if ((req->bmRequestType & cb[i].type_mask) == cb[i].type) { + result = cb[i].cb(usbd_dev, req, + &(usbd_dev->control_state.ctrl_buf), + &(usbd_dev->control_state.ctrl_len), + &(usbd_dev->control_state.complete)); + if (result == USBD_REQ_HANDLED || + result == USBD_REQ_NOTSUPP) { + return result; + } + } + } + + /* Try standard request if not already handled. */ + return _usbd_standard_request(usbd_dev, req, + &(usbd_dev->control_state.ctrl_buf), + &(usbd_dev->control_state.ctrl_len)); +} + +/* Handle commands and read requests. */ +static void usb_control_setup_read(usbd_device *usbd_dev, + struct usb_setup_data *req) +{ + usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf; + usbd_dev->control_state.ctrl_len = req->wLength; + + if (usb_control_request_dispatch(usbd_dev, req)) { + if (usbd_dev->control_state.ctrl_len) { + /* Go to data out stage if handled. */ + usb_control_send_chunk(usbd_dev); + } else { + /* Go to status stage if handled. */ + usbd_ep_write_packet(usbd_dev, 0, NULL, 0); + usbd_dev->control_state.state = STATUS_IN; + } + } else { + /* Stall endpoint on failure. */ + stall_transaction(usbd_dev); + } +} + +static void usb_control_setup_write(usbd_device *usbd_dev, + struct usb_setup_data *req) +{ + if (req->wLength > usbd_dev->ctrl_buf_len) { + stall_transaction(usbd_dev); + return; + } + + /* Buffer into which to write received data. */ + usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf; + usbd_dev->control_state.ctrl_len = 0; + /* Wait for DATA OUT stage. */ + if (req->wLength > usbd_dev->desc->bMaxPacketSize0) { + usbd_dev->control_state.state = DATA_OUT; + } else { + usbd_dev->control_state.state = LAST_DATA_OUT; + } +} + +/* Do not appear to belong to the API, so are omitted from docs */ +/**@}*/ + +void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea) +{ + struct usb_setup_data *req = &usbd_dev->control_state.req; + (void)ea; + + usbd_dev->control_state.complete = NULL; + + if (usbd_ep_read_packet(usbd_dev, 0, req, 8) != 8) { + stall_transaction(usbd_dev); + return; + } + + if (req->wLength == 0) { + usb_control_setup_read(usbd_dev, req); + } else if (req->bmRequestType & 0x80) { + usb_control_setup_read(usbd_dev, req); + } else { + usb_control_setup_write(usbd_dev, req); + } +} + +void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea) +{ + (void)ea; + + switch (usbd_dev->control_state.state) { + case DATA_OUT: + if (usb_control_recv_chunk(usbd_dev) < 0) { + break; + } + if ((usbd_dev->control_state.req.wLength - + usbd_dev->control_state.ctrl_len) <= + usbd_dev->desc->bMaxPacketSize0) { + usbd_dev->control_state.state = LAST_DATA_OUT; + } + break; + case LAST_DATA_OUT: + if (usb_control_recv_chunk(usbd_dev) < 0) { + break; + } + /* + * We have now received the full data payload. + * Invoke callback to process. + */ + if (usb_control_request_dispatch(usbd_dev, + &(usbd_dev->control_state.req))) { + /* Got to status stage on success. */ + usbd_ep_write_packet(usbd_dev, 0, NULL, 0); + usbd_dev->control_state.state = STATUS_IN; + } else { + stall_transaction(usbd_dev); + } + break; + case STATUS_OUT: + usbd_ep_read_packet(usbd_dev, 0, NULL, 0); + usbd_dev->control_state.state = IDLE; + if (usbd_dev->control_state.complete) { + usbd_dev->control_state.complete(usbd_dev, + &(usbd_dev->control_state.req)); + } + usbd_dev->control_state.complete = NULL; + break; + default: + stall_transaction(usbd_dev); + } +} + +void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea) +{ + (void)ea; + struct usb_setup_data *req = &(usbd_dev->control_state.req); + + switch (usbd_dev->control_state.state) { + case DATA_IN: + usb_control_send_chunk(usbd_dev); + break; + case LAST_DATA_IN: + usbd_dev->control_state.state = STATUS_OUT; + break; + case STATUS_IN: + if (usbd_dev->control_state.complete) { + usbd_dev->control_state.complete(usbd_dev, + &(usbd_dev->control_state.req)); + } + + /* Exception: Handle SET ADDRESS function here... */ + if ((req->bmRequestType == 0) && + (req->bRequest == USB_REQ_SET_ADDRESS)) { + usbd_dev->driver->set_address(usbd_dev, req->wValue); + } + usbd_dev->control_state.state = IDLE; + break; + default: + stall_transaction(usbd_dev); + } +} + diff --git a/libopencm3/lib/usb/usb_f103.c b/libopencm3/lib/usb/usb_f103.c new file mode 100644 index 0000000..2985650 --- /dev/null +++ b/libopencm3/lib/usb/usb_f103.c @@ -0,0 +1,346 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include "usb_private.h" + +static usbd_device *stm32f103_usbd_init(void); +static void stm32f103_set_address(usbd_device *usbd_dev, uint8_t addr); +static void stm32f103_ep_setup(usbd_device *usbd_dev, uint8_t addr, + uint8_t type, uint16_t max_size, + void (*callback) (usbd_device *usbd_dev, + uint8_t ep)); +static void stm32f103_endpoints_reset(usbd_device *usbd_dev); +static void stm32f103_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, + uint8_t stall); +static uint8_t stm32f103_ep_stall_get(usbd_device *usbd_dev, uint8_t addr); +static void stm32f103_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, + uint8_t nak); +static uint16_t stm32f103_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len); +static uint16_t stm32f103_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len); +static void stm32f103_poll(usbd_device *usbd_dev); + +static uint8_t force_nak[8]; +static struct _usbd_device usbd_dev; + +const struct _usbd_driver stm32f103_usb_driver = { + .init = stm32f103_usbd_init, + .set_address = stm32f103_set_address, + .ep_setup = stm32f103_ep_setup, + .ep_reset = stm32f103_endpoints_reset, + .ep_stall_set = stm32f103_ep_stall_set, + .ep_stall_get = stm32f103_ep_stall_get, + .ep_nak_set = stm32f103_ep_nak_set, + .ep_write_packet = stm32f103_ep_write_packet, + .ep_read_packet = stm32f103_ep_read_packet, + .poll = stm32f103_poll, +}; + +/** Initialize the USB device controller hardware of the STM32. */ +static usbd_device *stm32f103_usbd_init(void) +{ + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN); + SET_REG(USB_CNTR_REG, 0); + SET_REG(USB_BTABLE_REG, 0); + SET_REG(USB_ISTR_REG, 0); + + /* Enable RESET, SUSPEND, RESUME and CTR interrupts. */ + SET_REG(USB_CNTR_REG, USB_CNTR_RESETM | USB_CNTR_CTRM | + USB_CNTR_SUSPM | USB_CNTR_WKUPM); + return &usbd_dev; +} + +static void stm32f103_set_address(usbd_device *dev, uint8_t addr) +{ + (void)dev; + /* Set device address and enable. */ + SET_REG(USB_DADDR_REG, (addr & USB_DADDR_ADDR) | USB_DADDR_ENABLE); +} + +/** + * Set the receive buffer size for a given USB endpoint. + * + * @param ep Index of endpoint to configure. + * @param size Size in bytes of the RX buffer. + */ +static void usb_set_ep_rx_bufsize(usbd_device *dev, uint8_t ep, uint32_t size) +{ + (void)dev; + if (size > 62) { + if (size & 0x1f) { + size -= 32; + } + USB_SET_EP_RX_COUNT(ep, (size << 5) | 0x8000); + } else { + if (size & 1) { + size++; + } + USB_SET_EP_RX_COUNT(ep, size << 10); + } +} + +static void stm32f103_ep_setup(usbd_device *dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*callback) (usbd_device *usbd_dev, + uint8_t ep)) +{ + /* Translate USB standard type codes to STM32. */ + const uint16_t typelookup[] = { + [USB_ENDPOINT_ATTR_CONTROL] = USB_EP_TYPE_CONTROL, + [USB_ENDPOINT_ATTR_ISOCHRONOUS] = USB_EP_TYPE_ISO, + [USB_ENDPOINT_ATTR_BULK] = USB_EP_TYPE_BULK, + [USB_ENDPOINT_ATTR_INTERRUPT] = USB_EP_TYPE_INTERRUPT, + }; + uint8_t dir = addr & 0x80; + addr &= 0x7f; + + /* Assign address. */ + USB_SET_EP_ADDR(addr, addr); + USB_SET_EP_TYPE(addr, typelookup[type]); + + if (dir || (addr == 0)) { + USB_SET_EP_TX_ADDR(addr, dev->pm_top); + if (callback) { + dev->user_callback_ctr[addr][USB_TRANSACTION_IN] = + (void *)callback; + } + USB_CLR_EP_TX_DTOG(addr); + USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_NAK); + dev->pm_top += max_size; + } + + if (!dir) { + USB_SET_EP_RX_ADDR(addr, dev->pm_top); + usb_set_ep_rx_bufsize(dev, addr, max_size); + if (callback) { + dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] = + (void *)callback; + } + USB_CLR_EP_RX_DTOG(addr); + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); + dev->pm_top += max_size; + } +} + +static void stm32f103_endpoints_reset(usbd_device *dev) +{ + int i; + + /* Reset all endpoints. */ + for (i = 1; i < 8; i++) { + USB_SET_EP_TX_STAT(i, USB_EP_TX_STAT_DISABLED); + USB_SET_EP_RX_STAT(i, USB_EP_RX_STAT_DISABLED); + } + dev->pm_top = 0x40 + (2 * dev->desc->bMaxPacketSize0); +} + +static void stm32f103_ep_stall_set(usbd_device *dev, uint8_t addr, + uint8_t stall) +{ + (void)dev; + if (addr == 0) { + USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL : + USB_EP_TX_STAT_NAK); + } + + if (addr & 0x80) { + addr &= 0x7F; + + USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL : + USB_EP_TX_STAT_NAK); + + /* Reset to DATA0 if clearing stall condition. */ + if (!stall) { + USB_CLR_EP_TX_DTOG(addr); + } + } else { + /* Reset to DATA0 if clearing stall condition. */ + if (!stall) { + USB_CLR_EP_RX_DTOG(addr); + } + + USB_SET_EP_RX_STAT(addr, stall ? USB_EP_RX_STAT_STALL : + USB_EP_RX_STAT_VALID); + } +} + +static uint8_t stm32f103_ep_stall_get(usbd_device *dev, uint8_t addr) +{ + (void)dev; + if (addr & 0x80) { + if ((*USB_EP_REG(addr & 0x7F) & USB_EP_TX_STAT) == + USB_EP_TX_STAT_STALL) { + return 1; + } + } else { + if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == + USB_EP_RX_STAT_STALL) { + return 1; + } + } + return 0; +} + +static void stm32f103_ep_nak_set(usbd_device *dev, uint8_t addr, uint8_t nak) +{ + (void)dev; + /* It does not make sence to force NAK on IN endpoints. */ + if (addr & 0x80) { + return; + } + + force_nak[addr] = nak; + + if (nak) { + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_NAK); + } else { + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); + } +} + +/** + * Copy a data buffer to packet memory. + * + * @param vPM Destination pointer into packet memory. + * @param buf Source pointer to data buffer. + * @param len Number of bytes to copy. + */ +static void usb_copy_to_pm(volatile void *vPM, const void *buf, uint16_t len) +{ + const uint16_t *lbuf = buf; + volatile uint16_t *PM = vPM; + + for (len = (len + 1) >> 1; len; PM += 2, lbuf++, len--) { + *PM = *lbuf; + } +} + +static uint16_t stm32f103_ep_write_packet(usbd_device *dev, uint8_t addr, + const void *buf, uint16_t len) +{ + (void)dev; + addr &= 0x7F; + + if ((*USB_EP_REG(addr) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID) { + return 0; + } + + usb_copy_to_pm(USB_GET_EP_TX_BUFF(addr), buf, len); + USB_SET_EP_TX_COUNT(addr, len); + USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID); + + return len; +} + +/** + * Copy a data buffer from packet memory. + * + * @param buf Source pointer to data buffer. + * @param vPM Destination pointer into packet memory. + * @param len Number of bytes to copy. + */ +static void usb_copy_from_pm(void *buf, const volatile void *vPM, uint16_t len) +{ + uint16_t *lbuf = buf; + const volatile uint16_t *PM = vPM; + uint8_t odd = len & 1; + + for (len >>= 1; len; PM += 2, lbuf++, len--) { + *lbuf = *PM; + } + + if (odd) { + *(uint8_t *) lbuf = *(uint8_t *) PM; + } +} + +static uint16_t stm32f103_ep_read_packet(usbd_device *dev, uint8_t addr, + void *buf, uint16_t len) +{ + (void)dev; + if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == USB_EP_RX_STAT_VALID) { + return 0; + } + + len = MIN(USB_GET_EP_RX_COUNT(addr) & 0x3ff, len); + usb_copy_from_pm(buf, USB_GET_EP_RX_BUFF(addr), len); + USB_CLR_EP_RX_CTR(addr); + + if (!force_nak[addr]) { + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); + } + + return len; +} + +static void stm32f103_poll(usbd_device *dev) +{ + uint16_t istr = *USB_ISTR_REG; + + if (istr & USB_ISTR_RESET) { + dev->pm_top = 0x40; + _usbd_reset(dev); + USB_CLR_ISTR_RESET(); + return; + } + + if (istr & USB_ISTR_CTR) { + uint8_t ep = istr & USB_ISTR_EP_ID; + uint8_t type = (istr & USB_ISTR_DIR) ? 1 : 0; + + if (type) { /* OUT or SETUP transaction */ + type += (*USB_EP_REG(ep) & USB_EP_SETUP) ? 1 : 0; + } else { /* IN transaction */ + USB_CLR_EP_TX_CTR(ep); + } + + if (dev->user_callback_ctr[ep][type]) { + dev->user_callback_ctr[ep][type] (dev, ep); + } else { + USB_CLR_EP_RX_CTR(ep); + } + } + + if (istr & USB_ISTR_SUSP) { + USB_CLR_ISTR_SUSP(); + if (dev->user_callback_suspend) { + dev->user_callback_suspend(); + } + } + + if (istr & USB_ISTR_WKUP) { + USB_CLR_ISTR_WKUP(); + if (dev->user_callback_resume) { + dev->user_callback_resume(); + } + } + + if (istr & USB_ISTR_SOF) { + if (dev->user_callback_sof) { + dev->user_callback_sof(); + } + USB_CLR_ISTR_SOF(); + } +} diff --git a/libopencm3/lib/usb/usb_f107.c b/libopencm3/lib/usb/usb_f107.c new file mode 100644 index 0000000..32aecab --- /dev/null +++ b/libopencm3/lib/usb/usb_f107.c @@ -0,0 +1,91 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include "usb_private.h" +#include "usb_fx07_common.h" + +/* Receive FIFO size in 32-bit words. */ +#define RX_FIFO_SIZE 128 + +static usbd_device *stm32f107_usbd_init(void); + +static struct _usbd_device usbd_dev; + +const struct _usbd_driver stm32f107_usb_driver = { + .init = stm32f107_usbd_init, + .set_address = stm32fx07_set_address, + .ep_setup = stm32fx07_ep_setup, + .ep_reset = stm32fx07_endpoints_reset, + .ep_stall_set = stm32fx07_ep_stall_set, + .ep_stall_get = stm32fx07_ep_stall_get, + .ep_nak_set = stm32fx07_ep_nak_set, + .ep_write_packet = stm32fx07_ep_write_packet, + .ep_read_packet = stm32fx07_ep_read_packet, + .poll = stm32fx07_poll, + .disconnect = stm32fx07_disconnect, + .base_address = USB_OTG_FS_BASE, + .set_address_before_status = 1, + .rx_fifo_size = RX_FIFO_SIZE, +}; + +/** Initialize the USB device controller hardware of the STM32. */ +static usbd_device *stm32f107_usbd_init(void) +{ + OTG_FS_GINTSTS = OTG_FS_GINTSTS_MMIS; + + OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_PHYSEL; + /* Enable VBUS sensing in device mode and power down the PHY. */ + OTG_FS_GCCFG |= OTG_FS_GCCFG_VBUSBSEN | OTG_FS_GCCFG_PWRDWN; + + /* Wait for AHB idle. */ + while (!(OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_AHBIDL)); + /* Do core soft reset. */ + OTG_FS_GRSTCTL |= OTG_FS_GRSTCTL_CSRST; + while (OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_CSRST); + + /* Force peripheral only mode. */ + OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_FDMOD | OTG_FS_GUSBCFG_TRDT_MASK; + + /* Full speed device. */ + OTG_FS_DCFG |= OTG_FS_DCFG_DSPD; + + /* Restart the PHY clock. */ + OTG_FS_PCGCCTL = 0; + + OTG_FS_GRXFSIZ = stm32f107_usb_driver.rx_fifo_size; + usbd_dev.fifo_mem_top = stm32f107_usb_driver.rx_fifo_size; + + /* Unmask interrupts for TX and RX. */ + OTG_FS_GAHBCFG |= OTG_FS_GAHBCFG_GINT; + OTG_FS_GINTMSK = OTG_FS_GINTMSK_ENUMDNEM | + OTG_FS_GINTMSK_RXFLVLM | + OTG_FS_GINTMSK_IEPINT | + OTG_FS_GINTMSK_USBSUSPM | + OTG_FS_GINTMSK_WUIM | + OTG_FS_GINTMSK_SOFM; + OTG_FS_DAINTMSK = 0xF; + OTG_FS_DIEPMSK = OTG_FS_DIEPMSK_XFRCM; + + return &usbd_dev; +} diff --git a/libopencm3/lib/usb/usb_f207.c b/libopencm3/lib/usb/usb_f207.c new file mode 100644 index 0000000..b27d3cd --- /dev/null +++ b/libopencm3/lib/usb/usb_f207.c @@ -0,0 +1,91 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include "usb_private.h" +#include "usb_fx07_common.h" + +/* Receive FIFO size in 32-bit words. */ +#define RX_FIFO_SIZE 512 + +static usbd_device *stm32f207_usbd_init(void); + +static struct _usbd_device usbd_dev; + +const struct _usbd_driver stm32f207_usb_driver = { + .init = stm32f207_usbd_init, + .set_address = stm32fx07_set_address, + .ep_setup = stm32fx07_ep_setup, + .ep_reset = stm32fx07_endpoints_reset, + .ep_stall_set = stm32fx07_ep_stall_set, + .ep_stall_get = stm32fx07_ep_stall_get, + .ep_nak_set = stm32fx07_ep_nak_set, + .ep_write_packet = stm32fx07_ep_write_packet, + .ep_read_packet = stm32fx07_ep_read_packet, + .poll = stm32fx07_poll, + .disconnect = stm32fx07_disconnect, + .base_address = USB_OTG_HS_BASE, + .set_address_before_status = 1, + .rx_fifo_size = RX_FIFO_SIZE, +}; + +/** Initialize the USB device controller hardware of the STM32. */ +static usbd_device *stm32f207_usbd_init(void) +{ + OTG_HS_GINTSTS = OTG_HS_GINTSTS_MMIS; + + OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_PHYSEL; + /* Enable VBUS sensing in device mode and power down the PHY. */ + OTG_HS_GCCFG |= OTG_HS_GCCFG_VBUSBSEN | OTG_HS_GCCFG_PWRDWN; + + /* Wait for AHB idle. */ + while (!(OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_AHBIDL)); + /* Do core soft reset. */ + OTG_HS_GRSTCTL |= OTG_HS_GRSTCTL_CSRST; + while (OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_CSRST); + + /* Force peripheral only mode. */ + OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_FDMOD | OTG_HS_GUSBCFG_TRDT_MASK; + + /* Full speed device. */ + OTG_HS_DCFG |= OTG_HS_DCFG_DSPD; + + /* Restart the PHY clock. */ + OTG_HS_PCGCCTL = 0; + + OTG_HS_GRXFSIZ = stm32f207_usb_driver.rx_fifo_size; + usbd_dev.fifo_mem_top = stm32f207_usb_driver.rx_fifo_size; + + /* Unmask interrupts for TX and RX. */ + OTG_HS_GAHBCFG |= OTG_HS_GAHBCFG_GINT; + OTG_HS_GINTMSK = OTG_HS_GINTMSK_ENUMDNEM | + OTG_HS_GINTMSK_RXFLVLM | + OTG_HS_GINTMSK_IEPINT | + OTG_HS_GINTMSK_USBSUSPM | + OTG_HS_GINTMSK_WUIM | + OTG_HS_GINTMSK_SOFM; + OTG_HS_DAINTMSK = 0xF; + OTG_HS_DIEPMSK = OTG_HS_DIEPMSK_XFRCM; + + return &usbd_dev; +} diff --git a/libopencm3/lib/usb/usb_fx07_common.c b/libopencm3/lib/usb/usb_fx07_common.c new file mode 100644 index 0000000..c54c7a3 --- /dev/null +++ b/libopencm3/lib/usb/usb_fx07_common.c @@ -0,0 +1,338 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "usb_private.h" +#include "usb_fx07_common.h" + +/* The FS core and the HS core have the same register layout. + * As the code can be used on both cores, the registers offset is modified + * according to the selected cores base address. */ +#define dev_base_address (usbd_dev->driver->base_address) +#define REBASE(x) MMIO32((x) + (dev_base_address)) +#define REBASE_FIFO(x) (&MMIO32((dev_base_address) + (OTG_FIFO(x)))) + +void stm32fx07_set_address(usbd_device *usbd_dev, uint8_t addr) +{ + REBASE(OTG_DCFG) = (REBASE(OTG_DCFG) & ~OTG_FS_DCFG_DAD) | (addr << 4); +} + +void stm32fx07_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*callback) (usbd_device *usbd_dev, uint8_t ep)) +{ + /* + * Configure endpoint address and type. Allocate FIFO memory for + * endpoint. Install callback funciton. + */ + uint8_t dir = addr & 0x80; + addr &= 0x7f; + + if (addr == 0) { /* For the default control endpoint */ + /* Configure IN part. */ + if (max_size >= 64) { + REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_64; + } else if (max_size >= 32) { + REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_32; + } else if (max_size >= 16) { + REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_16; + } else { + REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_8; + } + + REBASE(OTG_DIEPTSIZ0) = + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + REBASE(OTG_DIEPCTL0) |= + OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK; + + /* Configure OUT part. */ + usbd_dev->doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 | + OTG_FS_DIEPSIZ0_PKTCNT | + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + REBASE(OTG_DOEPTSIZ(0)) = usbd_dev->doeptsiz[0]; + REBASE(OTG_DOEPCTL(0)) |= + OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK; + + REBASE(OTG_GNPTXFSIZ) = ((max_size / 4) << 16) | + usbd_dev->driver->rx_fifo_size; + usbd_dev->fifo_mem_top += max_size / 4; + usbd_dev->fifo_mem_top_ep0 = usbd_dev->fifo_mem_top; + + return; + } + + if (dir) { + REBASE(OTG_DIEPTXF(addr)) = ((max_size / 4) << 16) | + usbd_dev->fifo_mem_top; + usbd_dev->fifo_mem_top += max_size / 4; + + REBASE(OTG_DIEPTSIZ(addr)) = + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + REBASE(OTG_DIEPCTL(addr)) |= + OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18) + | OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID + | (addr << 22) | max_size; + + if (callback) { + usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] = + (void *)callback; + } + } + + if (!dir) { + usbd_dev->doeptsiz[addr] = OTG_FS_DIEPSIZ0_PKTCNT | + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr]; + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA | + OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK | + OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size; + + if (callback) { + usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] = + (void *)callback; + } + } +} + +void stm32fx07_endpoints_reset(usbd_device *usbd_dev) +{ + /* The core resets the endpoints automatically on reset. */ + usbd_dev->fifo_mem_top = usbd_dev->fifo_mem_top_ep0; +} + +void stm32fx07_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall) +{ + if (addr == 0) { + if (stall) { + REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL; + } else { + REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL; + } + } + + if (addr & 0x80) { + addr &= 0x7F; + + if (stall) { + REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL; + } else { + REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL; + REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTLX_SD0PID; + } + } else { + if (stall) { + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_STALL; + } else { + REBASE(OTG_DOEPCTL(addr)) &= ~OTG_FS_DOEPCTL0_STALL; + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTLX_SD0PID; + } + } +} + +uint8_t stm32fx07_ep_stall_get(usbd_device *usbd_dev, uint8_t addr) +{ + /* Return non-zero if STALL set. */ + if (addr & 0x80) { + return (REBASE(OTG_DIEPCTL(addr & 0x7f)) & + OTG_FS_DIEPCTL0_STALL) ? 1 : 0; + } else { + return (REBASE(OTG_DOEPCTL(addr)) & + OTG_FS_DOEPCTL0_STALL) ? 1 : 0; + } +} + +void stm32fx07_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak) +{ + /* It does not make sence to force NAK on IN endpoints. */ + if (addr & 0x80) { + return; + } + + usbd_dev->force_nak[addr] = nak; + + if (nak) { + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_SNAK; + } else { + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_CNAK; + } +} + +uint16_t stm32fx07_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len) +{ + const uint32_t *buf32 = buf; + int i; + + addr &= 0x7F; + + /* Return if endpoint is already enabled. */ + if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_FS_DIEPSIZ0_PKTCNT) { + return 0; + } + + /* Enable endpoint for transmission. */ + REBASE(OTG_DIEPTSIZ(addr)) = OTG_FS_DIEPSIZ0_PKTCNT | len; + REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_EPENA | + OTG_FS_DIEPCTL0_CNAK; + volatile uint32_t *fifo = REBASE_FIFO(addr); + + /* Copy buffer to endpoint FIFO, note - memcpy does not work */ + for (i = len; i > 0; i -= 4) { + *fifo++ = *buf32++; + } + + return len; +} + +uint16_t stm32fx07_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len) +{ + int i; + uint32_t *buf32 = buf; + uint32_t extra; + + len = MIN(len, usbd_dev->rxbcnt); + usbd_dev->rxbcnt -= len; + + volatile uint32_t *fifo = REBASE_FIFO(addr); + for (i = len; i >= 4; i -= 4) { + *buf32++ = *fifo++; + } + + if (i) { + extra = *fifo++; + memcpy(buf32, &extra, i); + } + + REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr]; + REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA | + (usbd_dev->force_nak[addr] ? + OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK); + + return len; +} + +void stm32fx07_poll(usbd_device *usbd_dev) +{ + /* Read interrupt status register. */ + uint32_t intsts = REBASE(OTG_GINTSTS); + int i; + + if (intsts & OTG_FS_GINTSTS_ENUMDNE) { + /* Handle USB RESET condition. */ + REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_ENUMDNE; + usbd_dev->fifo_mem_top = usbd_dev->driver->rx_fifo_size; + _usbd_reset(usbd_dev); + return; + } + + /* Note: RX and TX handled differently in this device. */ + if (intsts & OTG_FS_GINTSTS_RXFLVL) { + /* Receive FIFO non-empty. */ + uint32_t rxstsp = REBASE(OTG_GRXSTSP); + uint32_t pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK; + if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) && + (pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP)) { + return; + } + + uint8_t ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK; + uint8_t type; + if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP) { + type = USB_TRANSACTION_SETUP; + } else { + type = USB_TRANSACTION_OUT; + } + + /* Save packet size for stm32f107_ep_read_packet(). */ + usbd_dev->rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4; + + /* + * FIXME: Why is a delay needed here? + * This appears to fix a problem where the first 4 bytes + * of the DATA OUT stage of a control transaction are lost. + */ + for (i = 0; i < 1000; i++) { + __asm__("nop"); + } + + if (usbd_dev->user_callback_ctr[ep][type]) { + usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep); + } + + /* Discard unread packet data. */ + for (i = 0; i < usbd_dev->rxbcnt; i += 4) { + (void)*REBASE_FIFO(ep); + } + + usbd_dev->rxbcnt = 0; + } + + /* + * There is no global interrupt flag for transmit complete. + * The XFRC bit must be checked in each OTG_FS_DIEPINT(x). + */ + for (i = 0; i < 4; i++) { /* Iterate over endpoints. */ + if (REBASE(OTG_DIEPINT(i)) & OTG_FS_DIEPINTX_XFRC) { + /* Transfer complete. */ + if (usbd_dev->user_callback_ctr[i] + [USB_TRANSACTION_IN]) { + usbd_dev->user_callback_ctr[i] + [USB_TRANSACTION_IN](usbd_dev, i); + } + + REBASE(OTG_DIEPINT(i)) = OTG_FS_DIEPINTX_XFRC; + } + } + + if (intsts & OTG_FS_GINTSTS_USBSUSP) { + if (usbd_dev->user_callback_suspend) { + usbd_dev->user_callback_suspend(); + } + REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_USBSUSP; + } + + if (intsts & OTG_FS_GINTSTS_WKUPINT) { + if (usbd_dev->user_callback_resume) { + usbd_dev->user_callback_resume(); + } + REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_WKUPINT; + } + + if (intsts & OTG_FS_GINTSTS_SOF) { + if (usbd_dev->user_callback_sof) { + usbd_dev->user_callback_sof(); + } + REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_SOF; + } +} + +void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected) +{ + if (disconnected) { + REBASE(OTG_DCTL) |= OTG_FS_DCTL_SDIS; + } else { + REBASE(OTG_DCTL) &= ~OTG_FS_DCTL_SDIS; + } +} diff --git a/libopencm3/lib/usb/usb_fx07_common.h b/libopencm3/lib/usb/usb_fx07_common.h new file mode 100644 index 0000000..31c4030 --- /dev/null +++ b/libopencm3/lib/usb/usb_fx07_common.h @@ -0,0 +1,39 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __USB_FX07_COMMON_H_ +#define __USB_FX07_COMMON_H_ + +void stm32fx07_set_address(usbd_device *usbd_dev, uint8_t addr); +void stm32fx07_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*callback)(usbd_device *usbd_dev, uint8_t ep)); +void stm32fx07_endpoints_reset(usbd_device *usbd_dev); +void stm32fx07_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall); +uint8_t stm32fx07_ep_stall_get(usbd_device *usbd_dev, uint8_t addr); +void stm32fx07_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak); +uint16_t stm32fx07_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len); +uint16_t stm32fx07_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len); +void stm32fx07_poll(usbd_device *usbd_dev); +void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected); + + +#endif /* __USB_FX07_COMMON_H_ */ diff --git a/libopencm3/lib/usb/usb_msc.c b/libopencm3/lib/usb/usb_msc.c new file mode 100644 index 0000000..573590d --- /dev/null +++ b/libopencm3/lib/usb/usb_msc.c @@ -0,0 +1,814 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2013 Weston Schmidt + * Copyright (C) 2013 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "usb_private.h" + +/* Definitions of Mass Storage Class from: + * + * (A) "Universal Serial Bus Mass Storage Class Bulk-Only Transport + * Revision 1.0" + * + * (B) "Universal Serial Bus Mass Storage Class Specification Overview + * Revision 1.0" + */ + +/* Command Block Wrapper */ +#define CBW_SIGNATURE 0x43425355 +#define CBW_STATUS_SUCCESS 0 +#define CBW_STATUS_FAILED 1 +#define CBW_STATUS_PHASE_ERROR 2 + +/* Command Status Wrapper */ +#define CSW_SIGNATURE 0x53425355 +#define CSW_STATUS_SUCCESS 0 +#define CSW_STATUS_FAILED 1 +#define CSW_STATUS_PHASE_ERROR 2 + +/* Implemented SCSI Commands */ +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_READ_6 0x08 +#define SCSI_WRITE_6 0x0A +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SENSE_6 0x1A +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_10 0x28 + + +/* Required SCSI Commands */ + +/* Optional SCSI Commands */ +#define SCSI_REPORT_LUNS 0xA0 +#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_MODE_SELECT_6 0x15 +#define SCSI_MODE_SELECT_10 0x55 +#define SCSI_MODE_SENSE_10 0x5A +#define SCSI_READ_12 0xA8 +#define SCSI_READ_FORMAT_CAPACITIES 0x23 +#define SCSI_READ_TOC_PMA_ATIP 0x43 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_SYNCHRONIZE_CACHE 0x35 +#define SCSI_VERIFY 0x2F +#define SCSI_WRITE_10 0x2A +#define SCSI_WRITE_12 0xAA + +/* The sense codes */ +enum sbc_sense_key { + SBC_SENSE_KEY_NO_SENSE = 0x00, + SBC_SENSE_KEY_RECOVERED_ERROR = 0x01, + SBC_SENSE_KEY_NOT_READY = 0x02, + SBC_SENSE_KEY_MEDIUM_ERROR = 0x03, + SBC_SENSE_KEY_HARDWARE_ERROR = 0x04, + SBC_SENSE_KEY_ILLEGAL_REQUEST = 0x05, + SBC_SENSE_KEY_UNIT_ATTENTION = 0x06, + SBC_SENSE_KEY_DATA_PROTECT = 0x07, + SBC_SENSE_KEY_BLANK_CHECK = 0x08, + SBC_SENSE_KEY_VENDOR_SPECIFIC = 0x09, + SBC_SENSE_KEY_COPY_ABORTED = 0x0A, + SBC_SENSE_KEY_ABORTED_COMMAND = 0x0B, + SBC_SENSE_KEY_VOLUME_OVERFLOW = 0x0D, + SBC_SENSE_KEY_MISCOMPARE = 0x0E +}; + +enum sbc_asc { + SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION = 0x00, + SBC_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03, + SBC_ASC_LOGICAL_UNIT_NOT_READY = 0x04, + SBC_ASC_UNRECOVERED_READ_ERROR = 0x11, + SBC_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20, + SBC_ASC_LBA_OUT_OF_RANGE = 0x21, + SBC_ASC_INVALID_FIELD_IN_CDB = 0x24, + SBC_ASC_WRITE_PROTECTED = 0x27, + SBC_ASC_NOT_READY_TO_READY_CHANGE = 0x28, + SBC_ASC_FORMAT_ERROR = 0x31, + SBC_ASC_MEDIUM_NOT_PRESENT = 0x3A +}; + +enum sbc_ascq { + SBC_ASCQ_NA = 0x00, + SBC_ASCQ_FORMAT_COMMAND_FAILED = 0x01, + SBC_ASCQ_INITIALIZING_COMMAND_REQUIRED = 0x02, + SBC_ASCQ_OPERATION_IN_PROGRESS = 0x07 +}; + +enum trans_event { + EVENT_CBW_VALID, + EVENT_NEED_STATUS +}; + +struct usb_msc_cbw { + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; + uint8_t bCBWLUN; + uint8_t bCBWCBLength; + uint8_t CBWCB[16]; +} __attribute__((packed)); + +struct usb_msc_csw { + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} __attribute__((packed)); + +struct sbc_sense_info { + uint8_t key; + uint8_t asc; + uint8_t ascq; +}; + +struct usb_msc_trans { + uint8_t cbw_cnt; /* Read until 31 bytes */ + union { + struct usb_msc_cbw cbw; + uint8_t buf[1]; + } cbw; + + uint32_t bytes_to_read; + uint32_t bytes_to_write; + uint32_t byte_count; /* Either read until equal to bytes_to_read or + write until equal to bytes_to_write. */ + uint32_t lba_start; + uint32_t block_count; + uint32_t current_block; + + uint8_t msd_buf[512]; + + bool csw_valid; + uint8_t csw_sent; /* Write until 13 bytes */ + union { + struct usb_msc_csw csw; + uint8_t buf[1]; + } csw; +}; + +struct _usbd_mass_storage { + usbd_device *usbd_dev; + uint8_t ep_in; + uint8_t ep_in_size; + uint8_t ep_out; + uint8_t ep_out_size; + + const char *vendor_id; + const char *product_id; + const char *product_revision_level; + uint32_t block_count; + + int (*read_block)(uint32_t lba, uint8_t *copy_to); + int (*write_block)(uint32_t lba, const uint8_t *copy_from); + + void (*lock)(void); + void (*unlock)(void); + + struct usb_msc_trans trans; + struct sbc_sense_info sense; +}; + +static usbd_mass_storage _mass_storage; + +/*-- SCSI Base Responses -----------------------------------------------------*/ + +static const uint8_t _spc3_inquiry_response[36] = { + 0x00, /* Byte 0: Peripheral Qualifier = 0, Peripheral Device Type = 0 */ + 0x80, /* Byte 1: RMB = 1, Reserved = 0 */ + 0x04, /* Byte 2: Version = 0 */ + 0x02, /* Byte 3: Obsolete = 0, NormACA = 0, HiSup = 0, Response Data Format = 2 */ + 0x20, /* Byte 4: Additional Length (n-4) = 31 + 4 */ + 0x00, /* Byte 5: SCCS = 0, ACC = 0, TPGS = 0, 3PC = 0, Reserved = 0, Protect = 0 */ + 0x00, /* Byte 6: BQue = 0, EncServ = 0, VS = 0, MultiP = 0, MChngr = 0, Obsolete = 0, Addr16 = 0 */ + 0x00, /* Byte 7: Obsolete = 0, Wbus16 = 0, Sync = 0, Linked = 0, CmdQue = 0, VS = 0 */ + /* Byte 8 - Byte 15: Vendor Identification */ + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + /* Byte 16 - Byte 31: Product Identification */ + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + /* Byte 32 - Byte 35: Product Revision Level */ + 0x20, 0x20, 0x20, 0x20 +}; + +static const uint8_t _spc3_request_sense[18] = { + 0x70, /* Byte 0: VALID = 0, Response Code = 112 */ + 0x00, /* Byte 1: Obsolete = 0 */ + 0x00, /* Byte 2: Filemark = 0, EOM = 0, ILI = 0, Reserved = 0, Sense Key = 0 */ + /* Byte 3 - Byte 6: Information = 0 */ + 0, 0, 0, 0, + 0x0a, /* Byte 7: Additional Sense Length = 10 */ + /* Byte 8 - Byte 11: Command Specific Info = 0 */ + 0, 0, 0, 0, + 0x00, /* Byte 12: Additional Sense Code (ASC) = 0 */ + 0x00, /* Byte 13: Additional Sense Code Qualifier (ASCQ) = 0 */ + 0x00, /* Byte 14: Field Replaceable Unit Code (FRUC) = 0 */ + 0x00, /* Byte 15: SKSV = 0, SenseKeySpecific[0] = 0 */ + 0x00, /* Byte 16: SenseKeySpecific[0] = 0 */ + 0x00 /* Byte 17: SenseKeySpecific[0] = 0 */ +}; + +/*-- SCSI Layer --------------------------------------------------------------*/ + +static void set_sbc_status(usbd_mass_storage *ms, + enum sbc_sense_key key, + enum sbc_asc asc, + enum sbc_ascq ascq) +{ + ms->sense.key = (uint8_t) key; + ms->sense.asc = (uint8_t) asc; + ms->sense.ascq = (uint8_t) ascq; +} + +static void set_sbc_status_good(usbd_mass_storage *ms) +{ + set_sbc_status(ms, + SBC_SENSE_KEY_NO_SENSE, + SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION, + SBC_ASCQ_NA); +} + +static uint8_t *get_cbw_buf(struct usb_msc_trans *trans) +{ + return &trans->cbw.cbw.CBWCB[0]; +} + +static void scsi_read_6(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + uint8_t *buf; + + buf = get_cbw_buf(trans); + + trans->lba_start = (buf[2] << 8) | buf[3]; + trans->block_count = buf[4]; + trans->current_block = 0; + + /* TODO: Check the lba & block_count for range. */ + + /* both are in terms of 512 byte blocks, so shift by 9 */ + trans->bytes_to_write = trans->block_count << 9; + + set_sbc_status_good(ms); + } +} + +static void scsi_write_6(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + (void) ms; + + if (EVENT_CBW_VALID == event) { + uint8_t *buf; + + buf = get_cbw_buf(trans); + + trans->lba_start = ((0x1f & buf[1]) << 16) | (buf[2] << 8) | buf[3]; + trans->block_count = buf[4]; + trans->current_block = 0; + + trans->bytes_to_read = trans->block_count << 9; + } +} + +static void scsi_write_10(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + (void) ms; + + if (EVENT_CBW_VALID == event) { + uint8_t *buf; + + buf = get_cbw_buf(trans); + + trans->lba_start = (buf[2] << 24) | (buf[3] << 16) | + (buf[4] << 8) | buf[5]; + trans->block_count = (buf[7] << 8) | buf[8]; + trans->current_block = 0; + + trans->bytes_to_read = trans->block_count << 9; + } +} + +static void scsi_read_10(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + uint8_t *buf; + + buf = get_cbw_buf(trans); + + trans->lba_start = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5]; + trans->block_count = (buf[7] << 8) | buf[8]; + + /* TODO: Check the lba & block_count for range. */ + + /* both are in terms of 512 byte blocks, so shift by 9 */ + trans->bytes_to_write = trans->block_count << 9; + + set_sbc_status_good(ms); + } +} + +static void scsi_read_capacity(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + trans->msd_buf[0] = ms->block_count >> 24; + trans->msd_buf[1] = 0xff & (ms->block_count >> 16); + trans->msd_buf[2] = 0xff & (ms->block_count >> 8); + trans->msd_buf[3] = 0xff & ms->block_count; + + /* Block size: 512 */ + trans->msd_buf[4] = 0; + trans->msd_buf[5] = 0; + trans->msd_buf[6] = 2; + trans->msd_buf[7] = 0; + trans->bytes_to_write = 8; + set_sbc_status_good(ms); + } +} + +static void scsi_format_unit(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + uint32_t i; + + memset(trans->msd_buf, 0, 512); + + for (i = 0; i < ms->block_count; i++) { + (*ms->write_block)(i, trans->msd_buf); + } + + set_sbc_status_good(ms); + } +} + +static void scsi_request_sense(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + uint8_t *buf; + + buf = &trans->cbw.cbw.CBWCB[0]; + + trans->bytes_to_write = buf[4]; /* allocation length */ + memcpy(trans->msd_buf, _spc3_request_sense, sizeof(_spc3_request_sense)); + + trans->msd_buf[2] = ms->sense.key; + trans->msd_buf[12] = ms->sense.asc; + trans->msd_buf[13] = ms->sense.ascq; + } +} + +static void scsi_mode_sense_6(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + (void) ms; + + if (EVENT_CBW_VALID == event) { +#if 0 + uint8_t *buf; + uint8_t page_code; + uint8_t allocation_length; + + buf = &trans->cbw.cbw.CBWCB[0]; + page_code = buf[2]; + allocation_length = buf[4]; + + if (0x1C == page_code) { /* Informational Exceptions */ +#endif + trans->bytes_to_write = 4; + + trans->msd_buf[0] = 3; /* Num bytes that follow */ + trans->msd_buf[1] = 0; /* Medium Type */ + trans->msd_buf[2] = 0; /* Device specific param */ + trans->csw.csw.dCSWDataResidue = 4; +#if 0 + } else if (0x01 == page_code) { /* Error recovery */ + } else if (0x3F == page_code) { /* All */ + } else { + /* Error */ + trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED; + set_sbc_status(ms, + SBC_SENSE_KEY_ILLEGAL_REQUEST, + SBC_ASC_INVALID_FIELD_IN_CDB, + SBC_ASCQ_NA); + } +#endif + } +} + +static void scsi_inquiry(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + uint8_t evpd; + uint8_t *buf; + + buf = get_cbw_buf(trans); + evpd = 1 & buf[1]; + + if (0 == evpd) { + size_t len; + trans->bytes_to_write = sizeof(_spc3_inquiry_response); + memcpy(trans->msd_buf, _spc3_inquiry_response, sizeof(_spc3_inquiry_response)); + + len = strlen(ms->vendor_id); + len = MIN(len, 8); + memcpy(&trans->msd_buf[8], ms->vendor_id, len); + + len = strlen(ms->product_id); + len = MIN(len, 16); + memcpy(&trans->msd_buf[16], ms->product_id, len); + + len = strlen(ms->product_revision_level); + len = MIN(len, 4); + memcpy(&trans->msd_buf[32], ms->product_revision_level, len); + + trans->csw.csw.dCSWDataResidue = sizeof(_spc3_inquiry_response); + + set_sbc_status_good(ms); + } else { + /* TODO: Add VPD 0x83 support */ + /* TODO: Add VPD 0x00 support */ + } + } +} + +static void scsi_command(usbd_mass_storage *ms, + struct usb_msc_trans *trans, + enum trans_event event) +{ + if (EVENT_CBW_VALID == event) { + /* Setup the default success */ + trans->csw_sent = 0; + trans->csw.csw.dCSWSignature = CSW_SIGNATURE; + trans->csw.csw.dCSWTag = trans->cbw.cbw.dCBWTag; + trans->csw.csw.dCSWDataResidue = 0; + trans->csw.csw.bCSWStatus = CSW_STATUS_SUCCESS; + + trans->bytes_to_write = 0; + trans->bytes_to_read = 0; + trans->byte_count = 0; + } + + switch (trans->cbw.cbw.CBWCB[0]) { + case SCSI_TEST_UNIT_READY: + case SCSI_SEND_DIAGNOSTIC: + /* Do nothing, just send the success. */ + set_sbc_status_good(ms); + break; + case SCSI_FORMAT_UNIT: + scsi_format_unit(ms, trans, event); + break; + case SCSI_REQUEST_SENSE: + scsi_request_sense(ms, trans, event); + break; + case SCSI_MODE_SENSE_6: + scsi_mode_sense_6(ms, trans, event); + break; + case SCSI_READ_6: + scsi_read_6(ms, trans, event); + break; + case SCSI_INQUIRY: + scsi_inquiry(ms, trans, event); + break; + case SCSI_READ_CAPACITY: + scsi_read_capacity(ms, trans, event); + break; + case SCSI_READ_10: + scsi_read_10(ms, trans, event); + break; + case SCSI_WRITE_6: + scsi_write_6(ms, trans, event); + break; + case SCSI_WRITE_10: + scsi_write_10(ms, trans, event); + break; + default: + set_sbc_status(ms, SBC_SENSE_KEY_ILLEGAL_REQUEST, + SBC_ASC_INVALID_COMMAND_OPERATION_CODE, + SBC_ASCQ_NA); + + trans->bytes_to_write = 0; + trans->bytes_to_read = 0; + trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED; + break; + } +} + +/*-- USB Mass Storage Layer --------------------------------------------------*/ + +/** @brief Handle the USB 'OUT' requests. */ +static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) +{ + usbd_mass_storage *ms; + struct usb_msc_trans *trans; + int len, max_len, left; + void *p; + + ms = &_mass_storage; + trans = &ms->trans; + + /* RX only */ + left = sizeof(struct usb_msc_cbw) - trans->cbw_cnt; + if (0 < left) { + max_len = MIN(ms->ep_out_size, left); + p = &trans->cbw.buf[0x1ff & trans->cbw_cnt]; + len = usbd_ep_read_packet(usbd_dev, ep, p, max_len); + trans->cbw_cnt += len; + + if (sizeof(struct usb_msc_cbw) == trans->cbw_cnt) { + scsi_command(ms, trans, EVENT_CBW_VALID); + if (trans->byte_count < trans->bytes_to_read) { + /* We must wait until there is something to + * read again. */ + return; + } + } + } + + if (trans->byte_count < trans->bytes_to_read) { + if (0 < trans->block_count) { + if ((0 == trans->byte_count) && (NULL != ms->lock)){ + (*ms->lock)(); + } + } + + left = trans->bytes_to_read - trans->byte_count; + max_len = MIN(ms->ep_out_size, left); + p = &trans->msd_buf[0x1ff & trans->byte_count]; + len = usbd_ep_read_packet(usbd_dev, ep, p, max_len); + trans->byte_count += len; + + if (0 < trans->block_count) { + if (0 == (0x1ff & trans->byte_count)) { + uint32_t lba; + + lba = trans->lba_start + trans->current_block; + if (0 != (*ms->write_block)(lba, trans->msd_buf)) { + /* Error */ + } + trans->current_block++; + } + } + } else if (trans->byte_count < trans->bytes_to_write) { + if (0 < trans->block_count) { + if ((0 == trans->byte_count) && (NULL != ms->lock)) { + (*ms->lock)(); + } + + if (0 == (0x1ff & trans->byte_count)) { + uint32_t lba; + + lba = trans->lba_start + trans->current_block; + if (0 != (*ms->read_block)(lba, trans->msd_buf)) { + /* Error */ + } + trans->current_block++; + } + } + + left = trans->bytes_to_write - trans->byte_count; + max_len = MIN(ms->ep_out_size, left); + p = &trans->msd_buf[0x1ff & trans->byte_count]; + len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len); + trans->byte_count += len; + } else { + if (0 < trans->block_count) { + if (trans->current_block == trans->block_count) { + uint32_t lba; + + lba = trans->lba_start + trans->current_block; + if (0 != (*ms->write_block)(lba, trans->msd_buf)) { + /* Error */ + } + + trans->current_block = 0; + if (NULL != ms->unlock){ + (*ms->unlock)(); + } + } + } + if (false == trans->csw_valid) { + scsi_command(ms, trans, EVENT_NEED_STATUS); + trans->csw_valid = true; + } + + left = sizeof(struct usb_msc_csw) - trans->csw_sent; + if (0 < left) { + max_len = MIN(ms->ep_out_size, left); + p = &trans->csw.buf[trans->csw_sent]; + len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len); + trans->csw_sent += len; + } + } +} + +/** @brief Handle the USB 'IN' requests. */ +static void msc_data_tx_cb(usbd_device *usbd_dev, uint8_t ep) +{ + usbd_mass_storage *ms; + struct usb_msc_trans *trans; + int len, max_len, left; + void *p; + + ms = &_mass_storage; + trans = &ms->trans; + + if (trans->byte_count < trans->bytes_to_write) { + if (0 < trans->block_count) { + if (0 == (0x1ff & trans->byte_count)) { + uint32_t lba; + + lba = trans->lba_start + trans->current_block; + if (0 != (*ms->read_block)(lba, trans->msd_buf)) { + /* Error */ + } + trans->current_block++; + } + } + + left = trans->bytes_to_write - trans->byte_count; + max_len = MIN(ms->ep_out_size, left); + p = &trans->msd_buf[0x1ff & trans->byte_count]; + len = usbd_ep_write_packet(usbd_dev, ep, p, max_len); + trans->byte_count += len; + } else { + if (0 < trans->block_count) { + if (trans->current_block == trans->block_count) { + trans->current_block = 0; + if (NULL != ms->unlock){ + (*ms->unlock)(); + } + } + } + if (false == trans->csw_valid) { + scsi_command(ms, trans, EVENT_NEED_STATUS); + trans->csw_valid = true; + } + + left = sizeof(struct usb_msc_csw) - trans->csw_sent; + if (0 < left) { + max_len = MIN(ms->ep_out_size, left); + p = &trans->csw.buf[trans->csw_sent]; + len = usbd_ep_write_packet(usbd_dev, ep, p, max_len); + trans->csw_sent += len; + } else if (sizeof(struct usb_msc_csw) == trans->csw_sent) { + /* End of transaction */ + trans->lba_start = 0xffffffff; + trans->block_count = 0; + trans->current_block = 0; + trans->cbw_cnt = 0; + trans->bytes_to_read = 0; + trans->bytes_to_write = 0; + trans->byte_count = 0; + trans->csw_sent = 0; + trans->csw_valid = false; + } + } +} + +/** @brief Handle various control requests related to the msc storage + * interface. + */ +static int msc_control_request(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + (void)complete; + (void)usbd_dev; + + switch (req->bRequest) { + case USB_MSC_REQ_BULK_ONLY_RESET: + /* Do any special reset code here. */ + return USBD_REQ_HANDLED; + case USB_MSC_REQ_GET_MAX_LUN: + /* Return the number of LUNs. We use 0. */ + *buf[0] = 0; + *len = 1; + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NOTSUPP; +} + +/** @brief Setup the endpoints to be bulk & register the callbacks. */ +static void msc_set_config(usbd_device *usbd_dev, uint16_t wValue) +{ + usbd_mass_storage *ms = &_mass_storage; + + (void)wValue; + + usbd_ep_setup(usbd_dev, ms->ep_in, USB_ENDPOINT_ATTR_BULK, + ms->ep_in_size, msc_data_tx_cb); + usbd_ep_setup(usbd_dev, ms->ep_out, USB_ENDPOINT_ATTR_BULK, + ms->ep_out_size, msc_data_rx_cb); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + msc_control_request); +} + +/** @addtogroup usb_msc */ +/** @{ */ + +/** @brief Initializes the USB Mass Storage subsystem. + +@note Currently you can only have this profile active. + +@param[in] usbd_dev The USB device to associate the Mass Storage with. +@param[in] ep_in The USB 'IN' endpoint. +@param[in] ep_in_size The maximum endpoint size. Valid values: 8, 16, 32 or 64 +@param[in] ep_out The USB 'OUT' endpoint. +@param[in] ep_out_size The maximum endpoint size. Valid values: 8, 16, 32 or 64 +@param[in] vendor_id The SCSI vendor ID to return. Maximum used length is 8. +@param[in] product_id The SCSI product ID to return. Maximum used length is 16. +@param[in] product_revision_level The SCSI product revision level to return. + Maximum used length is 4. +@param[in] block_count The number of 512-byte blocks available. +@param[in] read_block The function called when the host requests to read a LBA + block. Must _NOT_ be NULL. +@param[in] write_block The function called when the host requests to write a + LBA block. Must _NOT_ be NULL. + +@return Pointer to the usbd_mass_storage struct. +*/ +usbd_mass_storage *usb_msc_init(usbd_device *usbd_dev, + uint8_t ep_in, uint8_t ep_in_size, + uint8_t ep_out, uint8_t ep_out_size, + const char *vendor_id, + const char *product_id, + const char *product_revision_level, + const uint32_t block_count, + int (*read_block)(uint32_t lba, uint8_t *copy_to), + int (*write_block)(uint32_t lba, const uint8_t *copy_from)) +{ + _mass_storage.usbd_dev = usbd_dev; + _mass_storage.ep_in = ep_in; + _mass_storage.ep_in_size = ep_in_size; + _mass_storage.ep_out = ep_out; + _mass_storage.ep_out_size = ep_out_size; + _mass_storage.vendor_id = vendor_id; + _mass_storage.product_id = product_id; + _mass_storage.product_revision_level = product_revision_level; + _mass_storage.block_count = block_count - 1; + _mass_storage.read_block = read_block; + _mass_storage.write_block = write_block; + _mass_storage.lock = NULL; + _mass_storage.unlock = NULL; + + _mass_storage.trans.lba_start = 0xffffffff; + _mass_storage.trans.block_count = 0; + _mass_storage.trans.current_block = 0; + _mass_storage.trans.cbw_cnt = 0; + _mass_storage.trans.bytes_to_read = 0; + _mass_storage.trans.bytes_to_write = 0; + _mass_storage.trans.byte_count = 0; + _mass_storage.trans.csw_valid = false; + _mass_storage.trans.csw_sent = 0; + + set_sbc_status_good(&_mass_storage); + + usbd_register_set_config_callback(usbd_dev, msc_set_config); + + return &_mass_storage; +} + +/** @} */ diff --git a/libopencm3/lib/usb/usb_private.h b/libopencm3/lib/usb/usb_private.h new file mode 100644 index 0000000..81466df --- /dev/null +++ b/libopencm3/lib/usb/usb_private.h @@ -0,0 +1,163 @@ +/** @defgroup usb_private_defines USB Private Structures + +@brief Defined Constants and Types for the USB Private Structures + +@ingroup USB_defines + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#ifndef __USB_PRIVATE_H +#define __USB_PRIVATE_H + +#define MAX_USER_CONTROL_CALLBACK 4 +#define MAX_USER_SET_CONFIG_CALLBACK 4 + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/** Internal collection of device information. */ +struct _usbd_device { + const struct usb_device_descriptor *desc; + const struct usb_config_descriptor *config; + const char **strings; + int num_strings; + + uint8_t *ctrl_buf; /**< Internal buffer used for control transfers */ + uint16_t ctrl_buf_len; + + uint8_t current_address; + uint8_t current_config; + + uint16_t pm_top; /**< Top of allocated endpoint buffer memory */ + + /* User callback functions for various USB events */ + void (*user_callback_reset)(void); + void (*user_callback_suspend)(void); + void (*user_callback_resume)(void); + void (*user_callback_sof)(void); + + struct usb_control_state { + enum { + IDLE, STALLED, + DATA_IN, LAST_DATA_IN, STATUS_IN, + DATA_OUT, LAST_DATA_OUT, STATUS_OUT, + } state; + struct usb_setup_data req __attribute__((aligned(4))); + uint8_t *ctrl_buf; + uint16_t ctrl_len; + void (*complete)(usbd_device *usbd_dev, + struct usb_setup_data *req); + } control_state; + + struct user_control_callback { + usbd_control_callback cb; + uint8_t type; + uint8_t type_mask; + } user_control_callback[MAX_USER_CONTROL_CALLBACK]; + + void (*user_callback_ctr[8][3])(usbd_device *usbd_dev, uint8_t ea); + + /* User callback function for some standard USB function hooks */ + void (*user_callback_set_config[MAX_USER_SET_CONFIG_CALLBACK]) + (usbd_device *usbd_dev, uint16_t wValue); + + const struct _usbd_driver *driver; + + /* private driver data */ + + uint16_t fifo_mem_top; + uint16_t fifo_mem_top_ep0; + uint8_t force_nak[4]; + /* + * We keep a backup copy of the out endpoint size registers to restore + * them after a transaction. + */ + uint32_t doeptsiz[4]; + /* + * Received packet size for each endpoint. This is assigned in + * stm32f107_poll() which reads the packet status push register GRXSTSP + * for use in stm32f107_ep_read_packet(). + */ + uint16_t rxbcnt; +}; + +enum _usbd_transaction { + USB_TRANSACTION_IN, + USB_TRANSACTION_OUT, + USB_TRANSACTION_SETUP, +}; + +/* Do not appear to belong to the API, so are omitted from docs */ +/**@}*/ + +void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea); +void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea); +void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea); + +int _usbd_standard_request_device(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request_endpoint(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len); + +void _usbd_reset(usbd_device *usbd_dev); + +/* Functions provided by the hardware abstraction. */ +struct _usbd_driver { + usbd_device *(*init)(void); + void (*set_address)(usbd_device *usbd_dev, uint8_t addr); + void (*ep_setup)(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, + void (*cb)(usbd_device *usbd_dev, uint8_t ep)); + void (*ep_reset)(usbd_device *usbd_dev); + void (*ep_stall_set)(usbd_device *usbd_dev, uint8_t addr, + uint8_t stall); + void (*ep_nak_set)(usbd_device *usbd_dev, uint8_t addr, uint8_t nak); + uint8_t (*ep_stall_get)(usbd_device *usbd_dev, uint8_t addr); + uint16_t (*ep_write_packet)(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len); + uint16_t (*ep_read_packet)(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len); + void (*poll)(usbd_device *usbd_dev); + void (*disconnect)(usbd_device *usbd_dev, bool disconnected); + uint32_t base_address; + bool set_address_before_status; + uint16_t rx_fifo_size; +}; + +#endif + diff --git a/libopencm3/lib/usb/usb_standard.c b/libopencm3/lib/usb/usb_standard.c new file mode 100644 index 0000000..3b0dac9 --- /dev/null +++ b/libopencm3/lib/usb/usb_standard.c @@ -0,0 +1,532 @@ +/** @defgroup usb_standard_file Generic USB Standard Request Interface + +@ingroup USB + +@brief Generic USB Standard Request Interface + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include "usb_private.h" + +int usbd_register_set_config_callback(usbd_device *usbd_dev, + void (*callback)(usbd_device *usbd_dev, + uint16_t wValue)) +{ + int i; + + for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) { + if (usbd_dev->user_callback_set_config[i]) + continue; + + usbd_dev->user_callback_set_config[i] = callback; + return 0; + } + + return -1; +} + +static uint16_t build_config_descriptor(usbd_device *usbd_dev, + uint8_t index, uint8_t *buf, uint16_t len) +{ + uint8_t *tmpbuf = buf; + const struct usb_config_descriptor *cfg = &usbd_dev->config[index]; + uint16_t count, total = 0, totallen = 0; + uint16_t i, j, k; + + memcpy(buf, cfg, count = MIN(len, cfg->bLength)); + buf += count; + len -= count; + total += count; + totallen += cfg->bLength; + + /* For each interface... */ + for (i = 0; i < cfg->bNumInterfaces; i++) { + /* Interface Association Descriptor, if any */ + if (cfg->interface[i].iface_assoc) { + const struct usb_iface_assoc_descriptor *assoc = + cfg->interface[i].iface_assoc; + memcpy(buf, assoc, count = MIN(len, assoc->bLength)); + buf += count; + len -= count; + total += count; + totallen += assoc->bLength; + } + /* For each alternate setting... */ + for (j = 0; j < cfg->interface[i].num_altsetting; j++) { + const struct usb_interface_descriptor *iface = + &cfg->interface[i].altsetting[j]; + /* Copy interface descriptor. */ + memcpy(buf, iface, count = MIN(len, iface->bLength)); + buf += count; + len -= count; + total += count; + totallen += iface->bLength; + /* Copy extra bytes (function descriptors). */ + memcpy(buf, iface->extra, + count = MIN(len, iface->extralen)); + buf += count; + len -= count; + total += count; + totallen += iface->extralen; + /* For each endpoint... */ + for (k = 0; k < iface->bNumEndpoints; k++) { + const struct usb_endpoint_descriptor *ep = + &iface->endpoint[k]; + memcpy(buf, ep, count = MIN(len, ep->bLength)); + buf += count; + len -= count; + total += count; + totallen += ep->bLength; + } + } + } + + /* Fill in wTotalLength. */ + *(uint16_t *)(tmpbuf + 2) = totallen; + + return total; +} + +static int usb_descriptor_type(uint16_t wValue) +{ + return wValue >> 8; +} + +static int usb_descriptor_index(uint16_t wValue) +{ + return wValue & 0xFF; +} + +static int usb_standard_get_descriptor(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + int i, array_idx, descr_idx; + struct usb_string_descriptor *sd; + + descr_idx = usb_descriptor_index(req->wValue); + + switch (usb_descriptor_type(req->wValue)) { + case USB_DT_DEVICE: + *buf = (uint8_t *) usbd_dev->desc; + *len = MIN(*len, usbd_dev->desc->bLength); + return USBD_REQ_HANDLED; + case USB_DT_CONFIGURATION: + *buf = usbd_dev->ctrl_buf; + *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len); + return USBD_REQ_HANDLED; + case USB_DT_STRING: + sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf; + + if (descr_idx == 0) { + /* Send sane Language ID descriptor... */ + sd->wData[0] = USB_LANGID_ENGLISH_US; + sd->bLength = sizeof(sd->bLength) + + sizeof(sd->bDescriptorType) + + sizeof(sd->wData[0]); + + *len = MIN(*len, sd->bLength); + } else { + array_idx = descr_idx - 1; + + if (!usbd_dev->strings) { + /* Device doesn't support strings. */ + return USBD_REQ_NOTSUPP; + } + + /* Check that string index is in range. */ + if (array_idx >= usbd_dev->num_strings) { + return USBD_REQ_NOTSUPP; + } + + /* Strings with Language ID differnet from + * USB_LANGID_ENGLISH_US are not supported */ + if (req->wIndex != USB_LANGID_ENGLISH_US) { + return USBD_REQ_NOTSUPP; + } + + /* Ths string is returned as UTF16, hence the + * multiplication + */ + sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 + + sizeof(sd->bLength) + + sizeof(sd->bDescriptorType); + + *len = MIN(*len, sd->bLength); + + for (i = 0; i < (*len / 2) - 1; i++) { + sd->wData[i] = + usbd_dev->strings[array_idx][i]; + } + } + + sd->bDescriptorType = USB_DT_STRING; + *buf = (uint8_t *)sd; + + return USBD_REQ_HANDLED; + } + return USBD_REQ_NOTSUPP; +} + +static int usb_standard_set_address(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + (void)req; + (void)buf; + (void)len; + + /* The actual address is only latched at the STATUS IN stage. */ + if ((req->bmRequestType != 0) || (req->wValue >= 128)) { + return 0; + } + + usbd_dev->current_address = req->wValue; + + /* + * Special workaround for STM32F10[57] that require the address + * to be set here. This is undocumented! + */ + if (usbd_dev->driver->set_address_before_status) { + usbd_dev->driver->set_address(usbd_dev, req->wValue); + } + + return 1; +} + +static int usb_standard_set_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + int i; + + (void)req; + (void)buf; + (void)len; + + /* Is this correct, or should we reset alternate settings. */ + if (req->wValue == usbd_dev->current_config) { + return 1; + } + + usbd_dev->current_config = req->wValue; + + /* Reset all endpoints. */ + usbd_dev->driver->ep_reset(usbd_dev); + + if (usbd_dev->user_callback_set_config) { + /* + * Flush control callbacks. These will be reregistered + * by the user handler. + */ + for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + usbd_dev->user_control_callback[i].cb = NULL; + } + + for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) { + if (usbd_dev->user_callback_set_config[i]) { + usbd_dev->user_callback_set_config[i](usbd_dev, + req->wValue); + } + } + } + + return 1; +} + +static int usb_standard_get_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)req; + + if (*len > 1) { + *len = 1; + } + (*buf)[0] = usbd_dev->current_config; + + return 1; +} + +static int usb_standard_set_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + (void)buf; + + /* FIXME: Adapt if we have more than one interface. */ + if (req->wValue != 0) { + return 0; + } + *len = 0; + + return 1; +} + +static int usb_standard_get_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + (void)buf; + + /* FIXME: Adapt if we have more than one interface. */ + *len = 1; + (*buf)[0] = 0; + + return 1; +} + +static int usb_standard_device_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + + /* bit 0: self powered */ + /* bit 1: remote wakeup */ + if (*len > 2) { + *len = 2; + } + (*buf)[0] = 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_interface_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + /* not defined */ + + if (*len > 2) { + *len = 2; + } + (*buf)[0] = 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_endpoint_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)req; + + if (*len > 2) { + *len = 2; + } + (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_endpoint_stall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)buf; + (void)len; + + usbd_ep_stall_set(usbd_dev, req->wIndex, 1); + + return 1; +} + +static int usb_standard_endpoint_unstall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)buf; + (void)len; + + usbd_ep_stall_set(usbd_dev, req->wIndex, 0); + + return 1; +} + +/* Do not appear to belong to the API, so are omitted from docs */ +/**@}*/ + +int _usbd_standard_request_device(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (req->wValue == USB_FEAT_DEVICE_REMOTE_WAKEUP) { + /* Device wakeup code goes here. */ + } + + if (req->wValue == USB_FEAT_TEST_MODE) { + /* Test mode code goes here. */ + } + + break; + case USB_REQ_SET_ADDRESS: + /* + * SET ADDRESS is an exception. + * It is only processed at STATUS stage. + */ + command = usb_standard_set_address; + break; + case USB_REQ_SET_CONFIGURATION: + command = usb_standard_set_configuration; + break; + case USB_REQ_GET_CONFIGURATION: + command = usb_standard_get_configuration; + break; + case USB_REQ_GET_DESCRIPTOR: + command = usb_standard_get_descriptor; + break; + case USB_REQ_GET_STATUS: + /* + * GET_STATUS always responds with zero reply. + * The application may override this behaviour. + */ + command = usb_standard_device_get_status; + break; + case USB_REQ_SET_DESCRIPTOR: + /* SET_DESCRIPTOR is optional and not implemented. */ + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + /* not defined */ + break; + case USB_REQ_GET_INTERFACE: + command = usb_standard_get_interface; + break; + case USB_REQ_SET_INTERFACE: + command = usb_standard_set_interface; + break; + case USB_REQ_GET_STATUS: + command = usb_standard_interface_get_status; + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request_endpoint(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + if (req->wValue == USB_FEAT_ENDPOINT_HALT) { + command = usb_standard_endpoint_unstall; + } + break; + case USB_REQ_SET_FEATURE: + if (req->wValue == USB_FEAT_ENDPOINT_HALT) { + command = usb_standard_endpoint_stall; + } + break; + case USB_REQ_GET_STATUS: + command = usb_standard_endpoint_get_status; + break; + case USB_REQ_SET_SYNCH_FRAME: + /* FIXME: SYNCH_FRAME is not implemented. */ + /* + * SYNCH_FRAME is used for synchronization of isochronous + * endpoints which are not yet implemented. + */ + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + /* FIXME: Have class/vendor requests as well. */ + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return 0; + } + + switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) { + case USB_REQ_TYPE_DEVICE: + return _usbd_standard_request_device(usbd_dev, req, buf, len); + case USB_REQ_TYPE_INTERFACE: + return _usbd_standard_request_interface(usbd_dev, req, + buf, len); + case USB_REQ_TYPE_ENDPOINT: + return _usbd_standard_request_endpoint(usbd_dev, req, buf, len); + default: + return 0; + } +} + -- cgit v1.2.3