Initial fw commit

This commit is contained in:
jaseg 2020-10-11 23:31:12 +02:00
parent 0e25682ed7
commit 226fef1618
17 changed files with 4845 additions and 0 deletions

11
fw/.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
*.elf
*.o
*.expand
*.hex
*.lst
*.map
*.bin
sources.c
sources.tar.xz
sources.tar.xz.zip
.ipynb_checkpoints

104
fw/Makefile Normal file
View file

@ -0,0 +1,104 @@
# Megumin LED display firmware
# Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
CUBE_PATH ?= $(wildcard ~)/resource/STM32CubeF0
CMSIS_PATH ?= $(CUBE_PATH)/Drivers/CMSIS
CMSIS_DEV_PATH ?= $(CMSIS_PATH)/Device/ST/STM32F0xx
HAL_PATH ?= $(CUBE_PATH)/Drivers/STM32F0xx_HAL_Driver
MAC_ADDR ?= 0xdeadbeef
CC := arm-none-eabi-gcc
LD := arm-none-eabi-ld
OBJCOPY := arm-none-eabi-objcopy
OBJDUMP := arm-none-eabi-objdump
SIZE := arm-none-eabi-size
CFLAGS = -g -Wall -Wextra -std=gnu11 -O0
CFLAGS += -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb
#CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -nostartfiles
#LDFLAGS += -specs=rdimon.specs -DSEMIHOSTING
LDFLAGS += -Wl,-Map=main.map -nostdlib
#LDFLAGS += -Wl,--gc-sections
LIBS = -lgcc
#LIBS += -lrdimon
# Technically we're using an STM32F030F4, but apart from the TSSOP20 package that one is largely identical to the
# STM32F030*6 and there is no separate device header provided for it, so we're faking a *6 device here. This is
# even documented in stm32f0xx.h. Thanks ST!
CFLAGS += -DSTM32F030x6 -DHSE_VALUE=8000000
LDFLAGS += -Tstm32_flash.ld
CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused -I../common
LDFLAGS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM0l_math
###################################################
.PHONY: program clean
all: main.elf
cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/core_cm0.h
python3 tools/gen_cmsis_exports.py $^ > $@
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $^
# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^
%.o: %.s
$(CC) -c $(CFLAGS) -o $@ $^
# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^
sources.tar.xz: main.c Makefile
tar -caf $@ $^
# don't ask...
sources.tar.xz.zip: sources.tar.xz
zip $@ $^
sources.c: sources.tar.xz.zip
xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@
main.elf: main.c startup_stm32f030x6.s system_stm32f0xx.c $(HAL_PATH)/Src/stm32f0xx_ll_utils.c base.c cmsis_exports.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
$(OBJCOPY) -O ihex $@ $(@:.elf=.hex)
$(OBJCOPY) -O binary $@ $(@:.elf=.bin)
$(OBJDUMP) -St $@ >$(@:.elf=.lst)
$(SIZE) $@
program: main.elf openocd.cfg
openocd -f openocd.cfg -c "program $< verify reset exit"
8b10b_test_encode: 8b10b_test_encode.c 8b10b.c
gcc -o $@ $^
8b10b_test_decode: 8b10b_test_decode.c 8b10b.c
gcc -o $@ $^
protocol_test: protocol.c protocol_test.c
gcc -o $@ -O0 -Wall -Wextra -g -I../common $^
clean:
rm -f **.o
rm -f main.elf main.hex main.bin main.map main.lst
rm -f **.expand
rm -f cmsis_exports.c
rm -f sources.tar.xz
rm -f sources.tar.xz.zip
rm -f sources.c
rm -f protocol_test

2615
fw/Scope.ipynb Normal file

File diff suppressed because one or more lines are too long

25
fw/base.c Normal file
View file

@ -0,0 +1,25 @@
#include <unistd.h>
#include <stdbool.h>
int __errno = 0;
void *_impure_ptr = NULL;
void __sinit(void) {
}
void *memset(void *s, int c, size_t n) {
char *end = (char *)s + n;
for (char *p = (char *)s; p < end; p++)
*p = (char)c;
return s;
}
size_t strlen(const char *s) {
const char *start = s;
while (*s++);
return s - start - 1;
}
void __assert_func(bool value) {
}

48
fw/cmsis_exports.c Normal file
View file

@ -0,0 +1,48 @@
#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__
#define __GENERATED_CMSIS_HEADER_EXPORTS__
#include <stm32f030x6.h>
/* stm32f030x6.h */
TIM_TypeDef *tim3 = TIM3;
TIM_TypeDef *tim14 = TIM14;
RTC_TypeDef *rtc = RTC;
WWDG_TypeDef *wwdg = WWDG;
IWDG_TypeDef *iwdg = IWDG;
I2C_TypeDef *i2c1 = I2C1;
PWR_TypeDef *pwr = PWR;
SYSCFG_TypeDef *syscfg = SYSCFG;
EXTI_TypeDef *exti = EXTI;
ADC_TypeDef *adc1 = ADC1;
ADC_Common_TypeDef *adc1_common = ADC1_COMMON;
ADC_Common_TypeDef *adc = ADC;
TIM_TypeDef *tim1 = TIM1;
SPI_TypeDef *spi1 = SPI1;
USART_TypeDef *usart1 = USART1;
TIM_TypeDef *tim16 = TIM16;
TIM_TypeDef *tim17 = TIM17;
DBGMCU_TypeDef *dbgmcu = DBGMCU;
DMA_TypeDef *dma1 = DMA1;
DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1;
DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2;
DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3;
DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4;
DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5;
FLASH_TypeDef *flash = FLASH;
OB_TypeDef *ob = OB;
RCC_TypeDef *rcc = RCC;
CRC_TypeDef *crc = CRC;
GPIO_TypeDef *gpioa = GPIOA;
GPIO_TypeDef *gpiob = GPIOB;
GPIO_TypeDef *gpioc = GPIOC;
GPIO_TypeDef *gpiod = GPIOD;
GPIO_TypeDef *gpiof = GPIOF;
#include <core_cm0.h>
/* core_cm0.h */
SCB_Type *scb = SCB;
SysTick_Type *systick = SysTick;
NVIC_Type *nvic = NVIC;
#endif//__GENERATED_CMSIS_HEADER_EXPORTS__

65
fw/global.h Normal file
View file

@ -0,0 +1,65 @@
/* Megumin LED display firmware
* Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GLOBAL_H__
#define __GLOBAL_H__
/* Workaround for sub-par ST libraries */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#include <stm32f0xx.h>
#include <stm32f0xx_ll_utils.h>
#include <stm32f0xx_ll_spi.h>
#pragma GCC diagnostic pop
#include <system_stm32f0xx.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
/* Microcontroller part number: STM32F030F4C6 */
/* Things used for module status reporting. */
#define FIRMWARE_VERSION 1
#define HARDWARE_VERSION 0
#define TS_CAL1 (*(uint16_t *)0x1FFFF7B8)
#define VREFINT_CAL (*(uint16_t *)0x1FFFF7BA)
#define VMEAS_R_HIGH 10000 /* kiloohms */
#define VMEAS_R_LOW 3300 /* kiloohms */
static inline uint16_t be16toh(uint16_t be16in) { return __builtin_bswap16(be16in); }
static inline uint16_t htobe16(uint16_t hostin) { return __builtin_bswap16(hostin); }
static inline uint16_t le16toh(uint16_t le16in) { return le16in; }
static inline uint16_t htole16(uint16_t hostin) { return hostin; }
static inline uint32_t be32toh(uint32_t be32in) { return __builtin_bswap32(be32in); }
static inline uint32_t htobe32(uint32_t hostin) { return __builtin_bswap32(hostin); }
static inline uint32_t le32toh(uint32_t le32in) { return le32in; }
static inline uint32_t htole32(uint32_t hostin) { return hostin; }
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) \
+ sizeof(typeof(int[1 - 2 * \
!!__builtin_types_compatible_p(typeof(arr), \
typeof(&arr[0]))])) * 0)
#endif/*__GLOBAL_H__*/

236
fw/i2c.c Normal file
View file

@ -0,0 +1,236 @@
// Inter-integrated circuit (I2C) management
#include "i2c.h"
// I2C timeout, about 2ms
#define I2C_TIMEOUT 200U
// Maximum NBYTES value
#define I2C_NBYTES_MAX 255U
// Count rough delay for timeouts
static uint32_t i2c_calc_delay(uint32_t delay) {
uint32_t cnt;
if (SystemCoreClock > 1000000U) {
cnt = (delay * ((SystemCoreClock / 1000000U) + 1U));
} else {
cnt = (((delay / 100U) + 1U) * ((SystemCoreClock / 10000U) + 1U));
}
return cnt;
}
// Check if target device is ready for communication
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// devAddr - target device address
// trials - number of trials (must not be zero)
// return:
// I2C_ERROR if there was a timeout during I2C operations, I2C_SUCCESS otherwise
i2cstatus i2c_is_device_ready(I2C_TypeDef* I2Cx, uint8_t devAddr, uint32_t trials) {
volatile uint32_t wait;
uint32_t delay_val = i2c_calc_delay(I2C_TIMEOUT);
uint32_t reg;
while (trials--) {
// Clear all flags
I2Cx->ICR = I2C_ICR_ALL;
// Generate START
i2c_genstart(I2Cx, devAddr);
// Wait for STOP, NACK or BERR
wait = delay_val;
while (!((reg = I2Cx->ISR) & (I2C_ISR_STOPF | I2C_ISR_NACKF | I2C_ISR_BERR)) && --wait);
if (wait == 0) { return I2C_ERROR; }
// Wait while STOP flag is reset
wait = delay_val;
while (!(I2Cx->ISR & I2C_ISR_STOPF) && --wait);
if (wait == 0) { return I2C_ERROR; }
// Clear the NACK, STOP and BERR flags
I2Cx->ICR = I2C_ICR_STOPCF | I2C_ICR_NACKCF | I2C_ICR_BERRCF;
// Check for BERR flag
if (reg & I2C_ISR_BERR) {
// Misplaced START/STOP? Perform a software reset of I2C
i2c_disable(I2Cx);
i2c_enable(I2Cx);
} else {
// Device responded if NACK flag is not set
if (!(reg & I2C_ISR_NACKF)) { return I2C_SUCCESS; }
}
}
return I2C_ERROR;
}
// Transmit an amount of data in master mode
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// pBbuf - pointer to the data buffer
// nbytes - number of bytes to transmit
// devAddr - address of target device
// flags - options for transmission, combination of I2C_TX_xx values:
// I2C_TX_NOSTART - don't generate START condition
// I2C_TX_NOSTOP - don't generate STOP condition
// I2C_TX_CONT - this flag indicates that transmission will be continued
// e.g. by calling this function again with NOSTART flag
// zero value - generate both START and STOP conditions
// return:
// I2C_ERROR if there was a timeout during I2C operations, I2C_SUCCESS otherwise
i2cstatus i2c_transmit(I2C_TypeDef* I2Cx, uint8_t devAddr, const uint8_t *pBuf, uint32_t nbytes, uint32_t flags) {
uint32_t reg;
uint32_t tx_count;
uint32_t delay_val = i2c_calc_delay(I2C_TIMEOUT);
volatile uint32_t wait;
// Clear all flags
I2Cx->ICR = I2C_ICR_ALL;
// Everything regarding to the transmission is in the CR2 register
reg = I2Cx->CR2;
reg &= ~I2C_CR2_ALL;
// Slave device address
reg |= (devAddr & I2C_CR2_SADD);
// Whether it need to generate START condition
if (!(flags & I2C_TX_NOSTART)) { reg |= I2C_CR2_START; }
// Whether it need to generate STOP condition
if ((flags & I2C_TX_CONT) || (nbytes > I2C_NBYTES_MAX)) {
reg |= I2C_CR2_RELOAD;
} else {
if (!(flags & I2C_TX_NOSTOP)) { reg |= I2C_CR2_AUTOEND; }
}
// Transfer length
tx_count = (nbytes > I2C_NBYTES_MAX) ? I2C_NBYTES_MAX : nbytes;
nbytes -= tx_count;
reg |= tx_count << I2C_CR2_NBYTES_Pos;
// Write a composed value to the I2C register
I2Cx->CR2 = reg;
// Transmit data
while (tx_count) {
// Wait until either TXIS or NACK flag is set
wait = delay_val;
while (!((reg = I2Cx->ISR) & (I2C_ISR_TXIS | I2C_ISR_NACKF)) && --wait);
if ((reg & I2C_ISR_NACKF) || (wait == 0)) { return I2C_ERROR; }
// Transmit byte
I2Cx->TXDR = *pBuf++;
tx_count--;
if ((tx_count == 0) && (nbytes != 0)) {
// Wait until TCR flag is set (Transfer Complete Reload)
wait = delay_val;
while (!(I2Cx->ISR & I2C_ISR_TCR) && --wait);
if (wait == 0) { return I2C_ERROR; }
// Configure next (or last) portion transfer
reg = I2Cx->CR2;
reg &= ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND);
if ((flags & I2C_TX_CONT) || (nbytes > I2C_NBYTES_MAX)) {
reg |= I2C_CR2_RELOAD;
} else {
if (!(flags & I2C_TX_NOSTOP)) { reg |= I2C_CR2_AUTOEND; }
}
tx_count = (nbytes > I2C_NBYTES_MAX) ? I2C_NBYTES_MAX : nbytes;
nbytes -= tx_count;
reg |= tx_count << I2C_CR2_NBYTES_Pos;
I2Cx->CR2 = reg;
}
}
// End of transmission
wait = delay_val;
while (!(I2Cx->ISR & (I2C_ISR_TC | I2C_ISR_TCR | I2C_ISR_STOPF)) && --wait);
return (wait) ? I2C_SUCCESS : I2C_ERROR;
}
// Receive an amount of data in master mode
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// buf - pointer to the data buffer
// nbytes - number of bytes to receive
// devAddr - address of target device
// return:
// I2C_ERROR if there was a timeout during I2C operations, I2C_SUCCESS otherwise
i2cstatus i2c_receive(I2C_TypeDef* I2Cx, uint8_t devAddr, uint8_t *pBuf, uint32_t nbytes) {
uint32_t reg;
uint32_t rx_count;
uint32_t delay_val = i2c_calc_delay(I2C_TIMEOUT);
volatile uint32_t wait;
// Clear all flags
I2Cx->ICR = I2C_ICR_ALL;
// Everything regarding to the transmission is in the CR2 register
reg = I2Cx->CR2;
reg &= ~I2C_CR2_ALL;
// Configure slave device address, enable START condition and set direction to READ
reg |= (devAddr & I2C_CR2_SADD) | I2C_CR2_START | I2C_CR2_RD_WRN;
// Transfer length
if (nbytes > I2C_NBYTES_MAX) {
rx_count = I2C_NBYTES_MAX;
reg |= I2C_CR2_RELOAD;
} else {
rx_count = nbytes;
reg |= I2C_CR2_AUTOEND;
}
reg |= rx_count << I2C_CR2_NBYTES_Pos;
nbytes -= rx_count;
// Write a composed value to the I2C register
I2Cx->CR2 = reg;
// Receive data
while (rx_count) {
// Wait until either RXNE or NACK flag is set
wait = delay_val;
while (!((reg = I2Cx->ISR) & (I2C_ISR_RXNE | I2C_ISR_NACKF)) && --wait);
if ((reg & I2C_ISR_NACKF) || (wait == 0)) { return I2C_ERROR; }
// Read received data
*pBuf++ = I2Cx->RXDR;
rx_count--;
if ((rx_count == 0) && (nbytes != 0)) {
// Wait until TCR flag is set (Transfer Complete Reload)
wait = delay_val;
while (!(I2Cx->ISR & I2C_ISR_TCR) && --wait);
if (wait == 0) { return I2C_ERROR; }
// Configure next (or last) portion transfer
reg = I2Cx->CR2;
reg &= ~(I2C_CR2_NBYTES | I2C_CR2_AUTOEND | I2C_CR2_RELOAD);
if (nbytes > I2C_NBYTES_MAX) {
rx_count = I2C_NBYTES_MAX;
reg |= I2C_CR2_RELOAD;
} else {
rx_count = nbytes;
reg |= I2C_CR2_AUTOEND;
}
reg |= rx_count << I2C_CR2_NBYTES_Pos;
nbytes -= rx_count;
I2Cx->CR2 = reg;
}
}
// Wait for the STOP flag
wait = delay_val;
while (!(I2Cx->ISR & I2C_ISR_STOPF) && --wait);
return (wait) ? I2C_SUCCESS : I2C_ERROR;
}

107
fw/i2c.h Normal file
View file

@ -0,0 +1,107 @@
#ifndef __I2C_H
#define __I2C_H
#include "global.h"
// Definitions of I2C analog filter state
#define I2C_AF_ENABLE ((uint32_t)0x00000000U) // Analog filter is enabled
#define I2C_AF_DISABLE I2C_CR1_ANFOFF // Analog filter is disabled
// Flags definitions for transmit function
#define I2C_TX_STOP ((uint32_t)0x00000000U) // Generate STOP condition
#define I2C_TX_NOSTOP ((uint32_t)0x10000000U) // Don't generate STOP condition
#define I2C_TX_NOSTART ((uint32_t)0x20000000U) // Don't generate START condition
#define I2C_TX_CONT ((uint32_t)0x40000000U) // The transmission will be continued
// Definitions for compatibility with old code using this library
#define I2C_GENSTOP_YES I2C_TX_STOP
#define I2C_GENSTOP_NO I2C_TX_NOSTOP
// Definition of bits to reset in CR2 register
#define I2C_CR2_ALL (I2C_CR2_SADD | \
I2C_CR2_NBYTES | \
I2C_CR2_RELOAD | \
I2C_CR2_AUTOEND | \
I2C_CR2_RD_WRN | \
I2C_CR2_START | \
I2C_CR2_STOP)
// Definition of all bits in ICR register (clear all I2C flags at once)
#define I2C_ICR_ALL (I2C_ICR_ADDRCF | \
I2C_ICR_ALERTCF | \
I2C_ICR_ARLOCF | \
I2C_ICR_BERRCF | \
I2C_ICR_NACKCF | \
I2C_ICR_OVRCF | \
I2C_ICR_PECCF | \
I2C_ICR_STOPCF | \
I2C_ICR_TIMOUTCF)
// Result of I2C functions
typedef enum {
I2C_ERROR = 0,
I2C_SUCCESS = !I2C_ERROR
} i2cstatus;
// Public functions and macros
// Enable I2C peripheral
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
static inline void i2c_enable(I2C_TypeDef* I2Cx) {
I2Cx->CR1 |= I2C_CR1_PE;
}
// Disable I2C peripheral
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
static inline void i2c_disable(I2C_TypeDef* I2Cx) {
I2Cx->CR1 &= ~I2C_CR1_PE;
}
// Configure I2C noise filters
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// af - analog filter state, I2C_AF_DISABLE or I2C_AF_ENABLE
// df - digital filter configuration, can be a value in range from 0 to 15
// zero value means the digital filter is disabled
// this values means filtering capability up to (df * ti2cclk)
// note: must be called only when I2C is disabled (PE bit in I2C_CR1 register is reset)
static inline void i2c_config_filters(I2C_TypeDef* I2Cx, uint32_t af, uint32_t df) {
I2Cx->CR1 &= ~(I2C_CR1_ANFOFF | I2C_CR1_DNF);
I2Cx->CR1 |= (af & I2C_CR1_ANFOFF) | ((df << I2C_CR1_DNF_Pos) & I2C_CR1_DNF);
}
// Configure the I2C timings (SDA setup/hold time and SCL high/low period)
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// timing - the value for I2C_TIMINGR register
// note: must be called only when I2C is disabled (PE bit in I2C_CR1 register is reset)
static inline void i2c_config_timing(I2C_TypeDef* I2Cx, uint32_t timing) {
I2Cx->TIMINGR = timing;
}
// Generate START condition
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
// addr - I2C device address
// note: 7-bit addressing mode
static inline void i2c_genstart(I2C_TypeDef* I2Cx, uint32_t addr) {
I2Cx->CR2 = (addr & I2C_CR2_SADD) | I2C_CR2_START | I2C_CR2_AUTOEND;
}
// Generate STOP condition
// input:
// I2Cx - pointer to the I2C peripheral (I2C1, etc.)
static inline void i2c_genstop(I2C_TypeDef* I2Cx) {
I2Cx->CR2 |= I2C_CR2_STOP;
}
// Function prototypes
i2cstatus i2c_is_device_ready(I2C_TypeDef* I2Cx, uint8_t devAddr, uint32_t Trials);
i2cstatus i2c_transmit(I2C_TypeDef* I2Cx, uint8_t devAddr, const uint8_t *pBuf, uint32_t nbytes, uint32_t flags);
i2cstatus i2c_receive(I2C_TypeDef* I2Cx, uint8_t devAddr, uint8_t *pBuf, uint32_t nbytes);
#endif // __I2C_H

97
fw/main.c Normal file
View file

@ -0,0 +1,97 @@
/* Megumin LED display firmware
* Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "global.h"
#include "i2c.h"
#include "mpu6050.h"
uint32_t pcg32_random_r() {
// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
static uint64_t state = 0xbc422715d3aef60f;
static uint64_t inc = 0x6605e3bc6d1a869b;
uint64_t oldstate = state;
// Advance internal state
state = oldstate * 6364136223846793005ULL + (inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
unsigned char dumb_random() {
static unsigned char x=0x66, a=0x05, b=0xe3, c=0xbc;
x++; //x is incremented every round and is not affected by any other variable
a = (a ^ c ^ x); //note the mix of addition and XOR
b = (b + a); //And the use of very few instructions
c = ((c + (b >> 1) ^ a)); // the AES S-Box Operation ensures an even distributon of entropy
return (c);
}
int main(void) {
/* We're starting out from HSI@8MHz */
SystemCoreClockUpdate();
/* Turn on lots of neat things */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
GPIOA->MODER |=
(1<<GPIO_MODER_MODER1_Pos)| /* PA1 - Port 1 */
(1<<GPIO_MODER_MODER2_Pos)| /* PA2 - Port 2 */
(1<<GPIO_MODER_MODER3_Pos)| /* PA3 - Port 3 */
(1<<GPIO_MODER_MODER4_Pos)| /* PA4 - Port 4 */
(1<<GPIO_MODER_MODER9_Pos); /* PA9 - LED */
int idx = 1;
while (1) {
GPIOA->ODR ^= (1<<9);
GPIOA->ODR = 2<<idx;
idx += 1;
if (idx > 4)
idx = 1;
for (size_t j=0; j<1000000; j++) {
asm volatile ("nop");
}
}
}
void gdb_dump(void) {
/* debugger hook */
}
void NMI_Handler(void) {
asm volatile ("bkpt");
}
void HardFault_Handler(void) __attribute__((naked));
void HardFault_Handler() {
asm volatile ("bkpt");
}
void SVC_Handler(void) {
asm volatile ("bkpt");
}
void PendSV_Handler(void) {
asm volatile ("bkpt");
}
void SysTick_Handler(void) {
asm volatile ("bkpt");
}

244
fw/mpu6050.c Normal file
View file

@ -0,0 +1,244 @@
/* MPU6050 device I2C library code for ARM STM32F103xx is placed under the MIT license
Copyright (c) 2012 Harinadha Reddy Chintalapalli
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "mpu6050.h"
#include "i2c.h"
/** @defgroup MPU_Library
* @{
*/
/** Power on and prepare for general usage.
* This will activate the device and take it out of sleep mode (which must be done
* after start-up). This function also sets both the accelerometer and the gyroscope
* to their most sensitive settings, namely +/- 2g and +/- 250 degrees/sec, and sets
* the clock source to use the X Gyro for reference, which is slightly better than
* the default internal clock source.
*/
void mpu_init()
{
mpu_reg_write(MPU_RA_PWR_MGMT1, MPU_CLOCK_PLL_XGYRO);
mpu_set_gyro_fs(MPU_GYRO_FS_250);
mpu_set_accel_fs(MPU_ACCEL_FS_2);
}
void mpu_init_low_power(uint8_t wake_freq, bool enable_interrupt)
{
mpu_set_gyro_fs(MPU_GYRO_FS_250);
mpu_set_accel_fs(MPU_ACCEL_FS_2);
/* For these two regs, see pwr mgmt reg 2 desc in reg map ref manual, pg. 42 */
mpu_reg_write(MPU_RA_PWR_MGMT1, MPU_PWR_MGMT1_CYCLE | MPU_PWR_MGMT1_TEMP_DIS | MPU_CLOCK_INTERNAL);
mpu_reg_write(MPU_RA_PWR_MGMT2, MPU_PWR_MGMT2_STBY_XG | MPU_PWR_MGMT2_STBY_YG | MPU_PWR_MGMT2_STBY_ZG | wake_freq);
if (enable_interrupt) {
mpu_reg_write(MPU_RA_INT_PIN_CFG, MPU_INT_PIN_CFG_RD_CLEAR);
mpu_reg_write(MPU_RA_INT_ENABLE, MPU_INT_ENABLE_DATA_RDY);
}
}
/** Verify the I2C connection.
* Make sure the device is connected and responds as expected.
* @return True if connection is valid, FALSE otherwise
*/
bool mpu_test_connection()
{
return mpu_device_id() == MPU_DEVICE_ID;
}
/** Get Device ID.
* This register is used to verify the identity of the device (0b110100).
* @return Device ID (should be 0x68, 104 dec, 150 oct)
* @see MPU_RA_WHO_AM_I
* @see MPU_WHO_AM_I_BIT
* @see MPU_WHO_AM_I_LENGTH
*/
uint8_t mpu_device_id()
{
return mpu_reg_read(MPU_RA_WHO_AM_I) >> MPU_WHO_AM_I_Pos;
}
/** Set full-scale gyroscope range.
* @param range New full-scale gyroscope range value
* @see MPU_GetFullScaleGyroRange()
* @see MPU_GYRO_FS_250
* @see MPU_RA_GYRO_CONFIG
* @see MPU_GCONFIG_FS_SEL_BIT
* @see MPU_GCONFIG_FS_SEL_LENGTH
*/
void mpu_set_gyro_fs(uint8_t range)
{
mpu_reg_write(MPU_RA_GYRO_CONFIG, range);
}
/** Get full-scale gyroscope range.
* The FS_SEL parameter allows setting the full-scale range of the gyro sensors,
* as described in the table below.
*
* <pre>
* 0 = +/- 250 degrees/sec
* 1 = +/- 500 degrees/sec
* 2 = +/- 1000 degrees/sec
* 3 = +/- 2000 degrees/sec
* </pre>
*
* @return Current full-scale gyroscope range setting
* @see MPU_GYRO_FS_250
* @see MPU_RA_GYRO_CONFIG
* @see MPU_GCONFIG_FS_SEL_BIT
* @see MPU_GCONFIG_FS_SEL_LENGTH
*/
uint8_t mpu_get_gyro_fs()
{
return mpu_reg_read(MPU_RA_GYRO_CONFIG) & MPU_GYRO_FS_SEL_Msk;
}
/** Get full-scale accelerometer range.
* The FS_SEL parameter allows setting the full-scale range of the accelerometer
* sensors, as described in the table below.
*
* <pre>
* 0 = +/- 2g
* 1 = +/- 4g
* 2 = +/- 8g
* 3 = +/- 16g
* </pre>
*
* @return Current full-scale accelerometer range setting
* @see MPU_ACCEL_FS_2
* @see MPU_RA_ACCEL_CONFIG
*/
uint8_t mpu_get_accel_fs()
{
return mpu_reg_read(MPU_RA_ACCEL_CONFIG) & MPU_ACCEL_CONFIG_FS_SEL_Msk;
}
/** Set full-scale accelerometer range.
* @param range New full-scale accelerometer range setting
* @see MPU_GetFullScaleAccelRange()
*/
void mpu_set_accel_fs(uint8_t range)
{
mpu_reg_write(MPU_RA_ACCEL_CONFIG, range);
}
/** Get sleep mode status.
* Setting the SLEEP bit in the register puts the device into very low power
* sleep mode. In this mode, only the serial interface and internal registers
* remain active, allowing for a very low standby current. Clearing this bit
* puts the device back into normal mode. To save power, the individual standby
* selections for each of the gyros should be used if any gyro axis is not used
* by the application.
* @return Current sleep mode bit
* @see MPU_RA_PWR_MGMT_1
* @see MPU_PWR1_SLEEP_BIT
*/
bool mpu_get_sleep_mode()
{
return mpu_reg_read(MPU_RA_PWR_MGMT1) & MPU_PWR_MGMT1_SLEEP;
}
/** Set sleep mode status.
* @param enabled New sleep mode enabled status
* @see MPU_GetSleepModeStatus()
* @see MPU_RA_PWR_MGMT_1
* @see MPU_PWR1_SLEEP_BIT
*/
void mpu_set_sleep_mode(bool val)
{
int tmp = mpu_reg_read(MPU_RA_PWR_MGMT1);
tmp = (tmp & ~MPU_PWR_MGMT1_SLEEP) | (val ? MPU_PWR_MGMT1_SLEEP : 0);
mpu_reg_write(MPU_RA_PWR_MGMT1, tmp);
}
/** Get raw 6-axis motion sensor readings (accel/gyro).
* Retrieves all currently available motion sensor values.
* @see MPU_RA_ACCEL_XOUT_H
*/
void mpu_read_accel_gyro(struct mpu_raw_data *out)
{
struct mpu_raw_data buf;
mpu_reg_read_multiple(MPU_RA_ACCEL_XOUT_H, (uint8_t *)&buf, sizeof(buf));
for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
}
int16_t mpu_read_temp() {
uint16_t buf;
mpu_reg_read_multiple(MPU_RA_TEMP_OUT_H, (uint8_t *)&buf, sizeof(buf));
return (int16_t)be16toh(buf);
}
void mpu_read_accel(struct mpu_accel_data *out)
{
struct mpu_accel_data buf;
mpu_reg_read_multiple(MPU_RA_ACCEL_XOUT_H, (uint8_t *)&buf, sizeof(buf));
for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
}
void mpu_read_gyro(struct mpu_gyro_data *out)
{
struct mpu_gyro_data buf;
mpu_reg_read_multiple(MPU_RA_GYRO_XOUT_H, (uint8_t *)&buf, sizeof(buf));
for (uint8_t i=0; i<ARRAY_SIZE(buf.channels); i++)
out->channels[i] = (int16_t)be16toh((uint16_t)buf.channels[i]);
}
/**
* @brief Writes one byte to the MPU6050.
* @param reg : address of the register in which the data will be written
* @param val : the data to be written to the MPU6050.
* @return None
*/
void mpu_reg_write(uint8_t reg, uint8_t val)
{
uint8_t tx[2] = {reg, val};
i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, tx, sizeof(tx), I2C_GENSTOP_YES);
}
/**
* @brief Reads a block of data from the MPU6050.
* @param buf : pointer to the buffer that receives the data read from the MPU6050.
* @param addr : MPU6050's internal address to read from.
* @param len : number of bytes to read from the MPU6050
* @return None
*/
void mpu_reg_read_multiple(uint8_t addr, uint8_t* buf, size_t len)
{
i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &addr, 1, I2C_GENSTOP_NO);
i2c_receive(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, buf, len);
}
uint8_t mpu_reg_read(uint8_t addr)
{
uint8_t buf;
i2c_transmit(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &addr, 1, I2C_GENSTOP_NO);
i2c_receive(MPU_I2C_PERIPH, MPU_DEFAULT_ADDRESS, &buf, 1);
return buf;
}
/**
* @}
*//* end of group MPU_Library */

491
fw/mpu6050.h Normal file
View file

@ -0,0 +1,491 @@
/* MPU6050 device I2C library code for ARM STM32F103xx is placed under the MIT license
Copyright (c) 2012 Harinadha Reddy Chintalapalli
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef __MPU6050_H
#define __MPU6050_H
#include "global.h"
#ifndef MPU_I2C_PERIPH
#define MPU_I2C_PERIPH I2C1
#endif
enum mpu_i2c_addr {
MPU_ADDRESS_AD0_LOW = 0xd0, // address pin low (GND), default for InvenSense evaluation board
MPU_ADDRESS_AD0_HIGH = 0xd1, // address pin high (VCC)
MPU_DEFAULT_ADDRESS = MPU_ADDRESS_AD0_LOW
};
enum mpu_reg_addr {
MPU_RA_XG_OFFS_TC = 0x00, //[7] PWR_MODE, [6:1] XG_OFFS_TC, [0] OTP_BNK_VLD
MPU_RA_YG_OFFS_TC = 0x01, //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
MPU_RA_ZG_OFFS_TC = 0x02, //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
MPU_RA_X_FINE_GAIN = 0x03, //[7:0] X_FINE_GAIN
MPU_RA_Y_FINE_GAIN = 0x04, //[7:0] Y_FINE_GAIN
MPU_RA_Z_FINE_GAIN = 0x05, //[7:0] Z_FINE_GAIN
MPU_RA_XA_OFFS_H = 0x06, //[15:0] XA_OFFS
MPU_RA_XA_OFFS_L_TC = 0x07,
MPU_RA_YA_OFFS_H = 0x08, //[15:0] YA_OFFS
MPU_RA_YA_OFFS_L_TC = 0x09,
MPU_RA_ZA_OFFS_H = 0x0A, //[15:0] ZA_OFFS
MPU_RA_ZA_OFFS_L_TC = 0x0B,
MPU_RA_XG_OFFS_USRH = 0x13, //[15:0] XG_OFFS_USR
MPU_RA_XG_OFFS_USRL = 0x14,
MPU_RA_YG_OFFS_USRH = 0x15, //[15:0] YG_OFFS_USR
MPU_RA_YG_OFFS_USRL = 0x16,
MPU_RA_ZG_OFFS_USRH = 0x17, //[15:0] ZG_OFFS_USR
MPU_RA_ZG_OFFS_USRL = 0x18,
MPU_RA_SMPLRT_DIV = 0x19,
MPU_RA_CONFIG = 0x1A,
MPU_RA_GYRO_CONFIG = 0x1B,
MPU_RA_ACCEL_CONFIG = 0x1C,
MPU_RA_FF_THR = 0x1D,
MPU_RA_FF_DUR = 0x1E,
MPU_RA_MOT_THR = 0x1F,
MPU_RA_MOT_DUR = 0x20,
MPU_RA_ZRMOT_THR = 0x21,
MPU_RA_ZRMOT_DUR = 0x22,
MPU_RA_FIFO_EN = 0x23,
MPU_RA_I2C_MST_CTRL = 0x24,
MPU_RA_I2C_SLV0_ADDR = 0x25,
MPU_RA_I2C_SLV0_REG = 0x26,
MPU_RA_I2C_SLV0_CTRL = 0x27,
MPU_RA_I2C_SLV1_ADDR = 0x28,
MPU_RA_I2C_SLV1_REG = 0x29,
MPU_RA_I2C_SLV1_CTRL = 0x2A,
MPU_RA_I2C_SLV2_ADDR = 0x2B,
MPU_RA_I2C_SLV2_REG = 0x2C,
MPU_RA_I2C_SLV2_CTRL = 0x2D,
MPU_RA_I2C_SLV3_ADDR = 0x2E,
MPU_RA_I2C_SLV3_REG = 0x2F,
MPU_RA_I2C_SLV3_CTRL = 0x30,
MPU_RA_I2C_SLV4_ADDR = 0x31,
MPU_RA_I2C_SLV4_REG = 0x32,
MPU_RA_I2C_SLV4_DO = 0x33,
MPU_RA_I2C_SLV4_CTRL = 0x34,
MPU_RA_I2C_SLV4_DI = 0x35,
MPU_RA_I2C_MST_STATUS = 0x36,
MPU_RA_INT_PIN_CFG = 0x37,
MPU_RA_INT_ENABLE = 0x38,
MPU_RA_DMP_INT_STATUS = 0x39,
MPU_RA_INT_STATUS = 0x3A,
MPU_RA_ACCEL_XOUT_H = 0x3B,
MPU_RA_ACCEL_XOUT_L = 0x3C,
MPU_RA_ACCEL_YOUT_H = 0x3D,
MPU_RA_ACCEL_YOUT_L = 0x3E,
MPU_RA_ACCEL_ZOUT_H = 0x3F,
MPU_RA_ACCEL_ZOUT_L = 0x40,
MPU_RA_TEMP_OUT_H = 0x41,
MPU_RA_TEMP_OUT_L = 0x42,
MPU_RA_GYRO_XOUT_H = 0x43,
MPU_RA_GYRO_XOUT_L = 0x44,
MPU_RA_GYRO_YOUT_H = 0x45,
MPU_RA_GYRO_YOUT_L = 0x46,
MPU_RA_GYRO_ZOUT_H = 0x47,
MPU_RA_GYRO_ZOUT_L = 0x48,
MPU_RA_EXT_SENS_DATA_00 = 0x49,
MPU_RA_EXT_SENS_DATA_01 = 0x4A,
MPU_RA_EXT_SENS_DATA_02 = 0x4B,
MPU_RA_EXT_SENS_DATA_03 = 0x4C,
MPU_RA_EXT_SENS_DATA_04 = 0x4D,
MPU_RA_EXT_SENS_DATA_05 = 0x4E,
MPU_RA_EXT_SENS_DATA_06 = 0x4F,
MPU_RA_EXT_SENS_DATA_07 = 0x50,
MPU_RA_EXT_SENS_DATA_08 = 0x51,
MPU_RA_EXT_SENS_DATA_09 = 0x52,
MPU_RA_EXT_SENS_DATA_10 = 0x53,
MPU_RA_EXT_SENS_DATA_11 = 0x54,
MPU_RA_EXT_SENS_DATA_12 = 0x55,
MPU_RA_EXT_SENS_DATA_13 = 0x56,
MPU_RA_EXT_SENS_DATA_14 = 0x57,
MPU_RA_EXT_SENS_DATA_15 = 0x58,
MPU_RA_EXT_SENS_DATA_16 = 0x59,
MPU_RA_EXT_SENS_DATA_17 = 0x5A,
MPU_RA_EXT_SENS_DATA_18 = 0x5B,
MPU_RA_EXT_SENS_DATA_19 = 0x5C,
MPU_RA_EXT_SENS_DATA_20 = 0x5D,
MPU_RA_EXT_SENS_DATA_21 = 0x5E,
MPU_RA_EXT_SENS_DATA_22 = 0x5F,
MPU_RA_EXT_SENS_DATA_23 = 0x60,
MPU_RA_MOT_DETECT_STATUS = 0x61,
MPU_RA_I2C_SLV0_DO = 0x63,
MPU_RA_I2C_SLV1_DO = 0x64,
MPU_RA_I2C_SLV2_DO = 0x65,
MPU_RA_I2C_SLV3_DO = 0x66,
MPU_RA_I2C_MST_DELAY_CTRL = 0x67,
MPU_RA_SIGNAL_PATH_RESET = 0x68,
MPU_RA_MOT_DETECT_CTRL = 0x69,
MPU_RA_USER_CTRL = 0x6A,
MPU_RA_PWR_MGMT1 = 0x6B,
MPU_RA_PWR_MGMT2 = 0x6C,
MPU_RA_BANK_SEL = 0x6D,
MPU_RA_MEM_START_ADDR = 0x6E,
MPU_RA_MEM_R_W = 0x6F,
MPU_RA_DMP_CFG1 = 0x70,
MPU_RA_DMP_CFG2 = 0x71,
MPU_RA_FIFO_COUNTH = 0x72,
MPU_RA_FIFO_COUNTL = 0x73,
MPU_RA_FIFO_R_W = 0x74,
MPU_RA_WHO_AM_I = 0x75,
};
enum mpu_tc {
MPU_TC_PWR_MODE_BIT = 7,
MPU_TC_OFFSET_BIT = 6,
MPU_TC_OFFSET_LENGTH = 6,
MPU_TC_OTP_BNK_VLD_BIT = 0,
};
enum mpu_vddio {
MPU_VDDIO_LEVEL_VLOGIC = 0,
MPU_VDDIO_LEVEL_VDD = 1,
};
enum mpu_cfg {
MPU_CFG_EXT_SYNC_SET_BIT = 5,
MPU_CFG_EXT_SYNC_SET_LENGTH = 3,
MPU_CFG_DLPF_CFG_BIT = 2,
MPU_CFG_DLPF_CFG_LENGTH = 3,
};
enum mpu_ext {
MPU_EXT_SYNC_DISABLED = 0x0,
MPU_EXT_SYNC_TEMP_OUT_L = 0x1,
MPU_EXT_SYNC_GYRO_XOUT_L = 0x2,
MPU_EXT_SYNC_GYRO_YOUT_L = 0x3,
MPU_EXT_SYNC_GYRO_ZOUT_L = 0x4,
MPU_EXT_SYNC_ACCEL_XOUT_L = 0x5,
MPU_EXT_SYNC_ACCEL_YOUT_L = 0x6,
MPU_EXT_SYNC_ACCEL_ZOUT_L = 0x7,
};
enum mpu_dlpf {
MPU_DLPF_BW_256 = 0x00,
MPU_DLPF_BW_188 = 0x01,
MPU_DLPF_BW_98 = 0x02,
MPU_DLPF_BW_42 = 0x03,
MPU_DLPF_BW_20 = 0x04,
MPU_DLPF_BW_10 = 0x05,
MPU_DLPF_BW_5 = 0x06,
};
enum mpu_gyro_config {
/* self test */
MPU_GYRO_XG_ST = 1<<7,
MPU_GYRO_YG_ST = 1<<6,
MPU_GYRO_ZG_ST = 1<<5,
/* full scale */
MPU_GYRO_FS_SEL_Pos = 3,
MPU_GYRO_FS_SEL_Msk = 3<<3,
MPU_GYRO_FS_250 = 0<<3,
MPU_GYRO_FS_500 = 1<<3,
MPU_GYRO_FS_1000 = 2<<3,
MPU_GYRO_FS_2000 = 3<<3,
/* dlpf config, default 0b00 */
MPU_GYRO_FCHOICE_B_Pos = 0,
MPU_GYRO_FCHOICE_B_Msk = 3<<0,
};
enum mpu_accel_config {
/* self test */
MPU_ACCEL_CONFIG_XA_ST = 1<<7,
MPU_ACCEL_CONFIG_YA_ST = 1<<6,
MPU_ACCEL_CONFIG_ZA_ST = 1<<5,
/* full scale */
MPU_ACCEL_CONFIG_FS_SEL_Pos = 3,
MPU_ACCEL_CONFIG_FS_SEL_Msk = 3<<3,
MPU_ACCEL_FS_2 = 0x00,
MPU_ACCEL_FS_4 = 0x01,
MPU_ACCEL_FS_8 = 0x02,
MPU_ACCEL_FS_16 = 0x03,
};
enum mpu_en {
MPU_TEMP_FIFO_EN_BIT = 7,
MPU_XG_FIFO_EN_BIT = 6,
MPU_YG_FIFO_EN_BIT = 5,
MPU_ZG_FIFO_EN_BIT = 4,
MPU_ACCEL_FIFO_EN_BIT = 3,
MPU_SLV2_FIFO_EN_BIT = 2,
MPU_SLV1_FIFO_EN_BIT = 1,
MPU_SLV0_FIFO_EN_BIT = 0,
MPU_MULT_MST_EN_BIT = 7,
MPU_WAIT_FOR_ES_BIT = 6,
MPU_SLV_3_FIFO_EN_BIT = 5,
MPU_I2C_MST_P_NSR_BIT = 4,
MPU_I2C_MST_CLK_BIT = 3,
MPU_I2C_MST_CLK_LENGTH = 4,
};
enum mpu_clkdiv {
MPU_CLOCK_DIV_348 = 0x0,
MPU_CLOCK_DIV_333 = 0x1,
MPU_CLOCK_DIV_320 = 0x2,
MPU_CLOCK_DIV_308 = 0x3,
MPU_CLOCK_DIV_296 = 0x4,
MPU_CLOCK_DIV_286 = 0x5,
MPU_CLOCK_DIV_276 = 0x6,
MPU_CLOCK_DIV_267 = 0x7,
MPU_CLOCK_DIV_258 = 0x8,
MPU_CLOCK_DIV_500 = 0x9,
MPU_CLOCK_DIV_471 = 0xA,
MPU_CLOCK_DIV_444 = 0xB,
MPU_CLOCK_DIV_421 = 0xC,
MPU_CLOCK_DIV_400 = 0xD,
MPU_CLOCK_DIV_381 = 0xE,
MPU_CLOCK_DIV_364 = 0xF,
};
enum mpu_i2c_slv {
MPU_I2C_SLV_RW_BIT = 7,
MPU_I2C_SLV_ADDR_BIT = 6,
MPU_I2C_SLV_ADDR_LENGTH = 7,
MPU_I2C_SLV_EN_BIT = 7,
MPU_I2C_SLV_BYTE_SW_BIT = 6,
MPU_I2C_SLV_REG_DIS_BIT = 5,
MPU_I2C_SLV_GRP_BIT = 4,
MPU_I2C_SLV_LEN_BIT = 3,
MPU_I2C_SLV_LEN_LENGTH = 4,
};
enum mpu_i2c_slv4 {
MPU_I2C_SLV4_RW_BIT = 7,
MPU_I2C_SLV4_ADDR_BIT = 6,
MPU_I2C_SLV4_ADDR_LENGTH = 7,
MPU_I2C_SLV4_EN_BIT = 7,
MPU_I2C_SLV4_INT_EN_BIT = 6,
MPU_I2C_SLV4_REG_DIS_BIT = 5,
MPU_I2C_SLV4_MST_DLY_BIT = 4,
MPU_I2C_SLV4_MST_DLY_LENGTH = 5,
};
enum mpu_mst {
MPU_MST_PASS_THROUGH_BIT = 7,
MPU_MST_I2C_SLV4_DONE_BIT = 6,
MPU_MST_I2C_LOST_ARB_BIT = 5,
MPU_MST_I2C_SLV4_NACK_BIT = 4,
MPU_MST_I2C_SLV3_NACK_BIT = 3,
MPU_MST_I2C_SLV2_NACK_BIT = 2,
MPU_MST_I2C_SLV1_NACK_BIT = 1,
MPU_MST_I2C_SLV0_NACK_BIT = 0,
};
enum mpu_intcfg {
MPU_INT_PIN_CFG_INT_LEVEL = 1<<7,
MPU_INTMODE_ACTIVEHIGH = 0,
MPU_INTMODE_ACTIVELOW = 1<<7,
MPU_INT_PIN_CFG_INT_OPEN = 1<<6,
MPU_INTDRV_PUSHPULL = 0,
MPU_INTDRV_OPENDRAIN = 1<<6,
MPU_INT_PIN_CFG_LATCH_INT_EN = 1<<5,
MPU_INTLATCH_50USPULSE = 0,
MPU_INTLATCH_WAITCLEAR = 1<<5,
MPU_INT_PIN_CFG_RD_CLEAR = 1<<4,
MPU_INTCLEAR_STATUSREAD = 0,
MPU_INTCLEAR_ANYREAD = 1<<4,
MPU_INT_PIN_CFG_FSYNC_INT_LEVEL = 1<<3,
MPU_INT_PIN_CFG_FSYNC_INT_EN = 1<<2,
MPU_INT_PIN_CFG_I2C_BYPASS_EN = 1<<1,
MPU_INT_PIN_CFG_CLKOUT_EN = 1<<0,
};
enum mpu_int_enable {
MPU_INT_ENABLE_FIFO_OFLOW = 1<<4,
MPU_INT_ENABLE_I2C_MST_INT = 1<<3,
MPU_INT_ENABLE_DATA_RDY = 1<<0,
};
// TODO: Need to work on DMP related things
enum mpu_dmpint {
MPU_DMPINT_5_BIT = 5,
MPU_DMPINT_4_BIT = 4,
MPU_DMPINT_3_BIT = 3,
MPU_DMPINT_2_BIT = 2,
MPU_DMPINT_1_BIT = 1,
MPU_DMPINT_0_BIT = 0,
};
enum mpu_motion {
MPU_MOTION_MOT_XNEG_BIT = 7,
MPU_MOTION_MOT_XPOS_BIT = 6,
MPU_MOTION_MOT_YNEG_BIT = 5,
MPU_MOTION_MOT_YPOS_BIT = 4,
MPU_MOTION_MOT_ZNEG_BIT = 3,
MPU_MOTION_MOT_ZPOS_BIT = 2,
MPU_MOTION_MOT_ZRMOT_BIT = 0,
};
enum mpu_delayctrl {
MPU_DELAYCTRL_DELAY_ES_SHADOW_BIT = 7,
MPU_DELAYCTRL_I2C_SLV4_DLY_EN_BIT = 4,
MPU_DELAYCTRL_I2C_SLV3_DLY_EN_BIT = 3,
MPU_DELAYCTRL_I2C_SLV2_DLY_EN_BIT = 2,
MPU_DELAYCTRL_I2C_SLV1_DLY_EN_BIT = 1,
MPU_DELAYCTRL_I2C_SLV0_DLY_EN_BIT = 0,
};
enum mpu_pathreset {
MPU_PATHRESET_GYRO_RESET_BIT = 2,
MPU_PATHRESET_ACCEL_RESET_BIT = 1,
MPU_PATHRESET_TEMP_RESET_BIT = 0,
};
enum mpu_detect {
MPU_DETECT_ACCEL_ON_DELAY_BIT = 5,
MPU_DETECT_ACCEL_ON_DELAY_LENGTH = 2,
MPU_DETECT_FF_COUNT_BIT = 3,
MPU_DETECT_FF_COUNT_LENGTH = 2,
MPU_DETECT_MOT_COUNT_BIT = 1,
MPU_DETECT_MOT_COUNT_LENGTH = 2,
MPU_DETECT_DECREMENT_RESET = 0x0,
MPU_DETECT_DECREMENT_1 = 0x1,
MPU_DETECT_DECREMENT_2 = 0x2,
MPU_DETECT_DECREMENT_4 = 0x3,
};
enum mpu_userctrl {
MPU_USERCTRL_DMP_EN_BIT = 7,
MPU_USERCTRL_FIFO_EN_BIT = 6,
MPU_USERCTRL_I2C_MST_EN_BIT = 5,
MPU_USERCTRL_I2C_IF_DIS_BIT = 4,
MPU_USERCTRL_DMP_RESET_BIT = 3,
MPU_USERCTRL_FIFO_RESET_BIT = 2,
MPU_USERCTRL_I2C_MST_RESET_BIT = 1,
MPU_USERCTRL_SIG_COND_RESET_BIT = 0,
};
enum mpu_pwr_mgmt1 {
MPU_PWR_MGMT1_DEVICE_RESET = 1<<7,
/* Low power sleep mode */
MPU_PWR_MGMT1_SLEEP = 1<<6,
/* Low power auto wakeup/cycle mode */
MPU_PWR_MGMT1_CYCLE = 1<<5,
/* Temperature sensor disable */
MPU_PWR_MGMT1_TEMP_DIS = 1<<3,
/* Clock source selection */
MPU_PWR_MGMT1_CLKSEL_Msk = 0x7,
MPU_PWR_MGMT1_CLKSEL_Pos = 0,
MPU_CLOCK_INTERNAL = 0,
MPU_CLOCK_PLL_XGYRO = 1,
MPU_CLOCK_PLL_YGYRO = 2,
MPU_CLOCK_PLL_ZGYRO = 3,
MPU_CLOCK_PLL_EXT32K = 4,
MPU_CLOCK_PLL_EXT19M = 5,
MPU_CLOCK_KEEP_RESET = 7,
};
enum mpu_pwr_mgmt2 {
/* low-power cyclic auto wakeup */
MPU_PWR_MGMT2_LP_WAKE_CTRL_Pos = 6,
MPU_PWR_MGMT2_LP_WAKE_CTRL_Msk = 3<<6,
MPU_WAKE_FREQ_1P25 = 0<<6,
MPU_WAKE_FREQ_5 = 1<<6,
MPU_WAKE_FREQ_20 = 2<<6,
MPU_WAKE_FREQ_40 = 3<<6,
/* axis standby bits */
MPU_PWR_MGMT2_STBY_XA = 1<<5,
MPU_PWR_MGMT2_STBY_YA = 1<<4,
MPU_PWR_MGMT2_STBY_ZA = 1<<3,
MPU_PWR_MGMT2_STBY_XG = 1<<2,
MPU_PWR_MGMT2_STBY_YG = 1<<1,
MPU_PWR_MGMT2_STBY_ZG = 1<<0,
};
enum mpu_banksel {
MPU_BANKSEL_PRFTCH_EN_BIT = 6,
MPU_BANKSEL_CFG_USER_BANK_BIT = 5,
MPU_BANKSEL_MEM_SEL_BIT = 4,
MPU_BANKSEL_MEM_SEL_LENGTH = 5,
};
enum mpu_whoami {
MPU_WHO_AM_I_Pos = 1,
MPU_WHO_AM_I_Msk = 0x3f<<1,
MPU_DEVICE_ID = 0x34,
};
enum mpu_dmp_mem {
MPU_DMP_MEMORY_BANKS = 8,
MPU_DMP_MEMORY_BANK_SIZE = 256,
MPU_DMP_MEMORY_CHUNK_SIZE = 16,
};
struct __attribute__((packed)) mpu_accel_data {
union {
struct { int16_t x, y, z; };
int16_t channels[3];
};
};
struct __attribute__((packed)) mpu_gyro_data {
union {
struct { int16_t x, y, z; };
int16_t channels[3];
};
};
struct __attribute__((packed)) mpu_raw_data {
union {
struct {
struct mpu_accel_data accel;
int16_t temp;
struct mpu_gyro_data gyro;
};
int16_t channels[7];
};
};
void mpu_init();
void mpu_init_low_power(uint8_t wake_freq, bool enable_interrupt);
bool mpu_test_connection();
uint8_t mpu_get_gyro_fs();
void mpu_set_gyro_fs(uint8_t range);
uint8_t mpu_get_accel_fs();
void mpu_set_accel_fs(uint8_t range);
// PWR_MGMT_1 register
bool mpu_get_sleep_mode();
void mpu_set_sleep_mode(bool val);
// WHO_AM_I register
uint8_t mpu_device_id();
void mpu_read_accel_gyro(struct mpu_raw_data *out);
int16_t mpu_read_temp();
void mpu_read_accel(struct mpu_accel_data *out);
void mpu_read_gyro(struct mpu_gyro_data *out);
void mpu_reg_write(uint8_t reg, uint8_t val);
void mpu_reg_read_multiple(uint8_t addr, uint8_t* buf, size_t len);
uint8_t mpu_reg_read(uint8_t addr);
#endif /* __MPU6050_H */

15
fw/openocd.cfg Normal file
View file

@ -0,0 +1,15 @@
telnet_port 4444
gdb_port 3333
source [find interface/stlink-v2.cfg]
#hla_serial "000000000001"
transport select hla_swd
source [find target/stm32f0x.cfg]
#adapter_khz 10000
init
arm semihosting enable
#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME
#program main.elf

12
fw/scope.gdb Normal file
View file

@ -0,0 +1,12 @@
target remote localhost:3333
set pagination off
file main.elf
load
break gdb_dump
command 1
dump binary value /tmp/scope_dump.bin debug_buf
continue
end
continue

273
fw/startup_stm32f030x6.s Normal file
View file

@ -0,0 +1,273 @@
/**
******************************************************************************
* @file startup_stm32f030x6.s
* copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc
* @author MCD Application Team
* @version V2.3.1
* @date 04-November-2016
* @brief STM32F030x4/STM32F030x6 devices vector table for Atollic TrueSTUDIO toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M0 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m0
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2]
adds r2, r2, #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
// bl __libc_init_array
/* Call the application's entry point.*/
bl main
LoopForever:
b LoopForever
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M0. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word 0
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler /* Window WatchDog */
.word 0 /* Reserved */
.word RTC_IRQHandler /* RTC through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
.word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
.word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
.word 0 /* Reserved */
.word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
.word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
.word DMA1_Channel4_5_IRQHandler /* DMA1 Channel 4 and Channel 5 */
.word ADC1_IRQHandler /* ADC1 */
.word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word 0 /* Reserved */
.word TIM3_IRQHandler /* TIM3 */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word TIM14_IRQHandler /* TIM14 */
.word 0 /* Reserved */
.word TIM16_IRQHandler /* TIM16 */
.word TIM17_IRQHandler /* TIM17 */
.word I2C1_IRQHandler /* I2C1 */
.word 0 /* Reserved */
.word SPI1_IRQHandler /* SPI1 */
.word 0 /* Reserved */
.word USART1_IRQHandler /* USART1 */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word 0 /* Reserved */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_1_IRQHandler
.thumb_set EXTI0_1_IRQHandler,Default_Handler
.weak EXTI2_3_IRQHandler
.thumb_set EXTI2_3_IRQHandler,Default_Handler
.weak EXTI4_15_IRQHandler
.thumb_set EXTI4_15_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_3_IRQHandler
.thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
.weak DMA1_Channel4_5_IRQHandler
.thumb_set DMA1_Channel4_5_IRQHandler,Default_Handler
.weak ADC1_IRQHandler
.thumb_set ADC1_IRQHandler,Default_Handler
.weak TIM1_BRK_UP_TRG_COM_IRQHandler
.thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM14_IRQHandler
.thumb_set TIM14_IRQHandler,Default_Handler
.weak TIM16_IRQHandler
.thumb_set TIM16_IRQHandler,Default_Handler
.weak TIM17_IRQHandler
.thumb_set TIM17_IRQHandler,Default_Handler
.weak I2C1_IRQHandler
.thumb_set I2C1_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

136
fw/stm32_flash.ld Normal file
View file

@ -0,0 +1,136 @@
ENTRY(Reset_Handler)
MEMORY {
FLASH (rx): ORIGIN = 0x08000000, LENGTH = 0x3C00
CONFIGFLASH (rw): ORIGIN = 0x08003C00, LENGTH = 0x400
RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
}
/* highest address of the user mode stack */
_estack = 0x20001000;
SECTIONS {
/* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
.isr_vector : {
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* the program code is stored in the .text section, which goes to Flash */
.text : {
. = ALIGN(4);
*(.text) /* normal code */
*(.text.*) /* -ffunction-sections code */
*(.rodata) /* read-only data (constants) */
*(.rodata*) /* -fdata-sections read only data */
*(.glue_7) /* TBD - needed ? */
*(.glue_7t) /* TBD - needed ? */
*(.source_tarball)
/* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */
KEEP (*(.init))
KEEP (*(.fini))
KEEP (*(.source_tarball))
. = ALIGN(4);
_etext = .;
/* This is used by the startup in order to initialize the .data section */
_sidata = _etext;
} >FLASH
/*
.configflash : {
. = ALIGN(0x400);
*(.configdata)
_econfig = .;
} >FLASH
*/
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata ) {
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_sdata = . ;
_data = . ;
*(.data)
*(.data.*)
*(.RAMtext)
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_edata = . ;
} >RAM
/* This is the uninitialized data section */
.bss : {
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .;
_bss = .;
*(.bss)
*(.bss.*) /* patched by elias - allows the use of -fdata-sections */
*(COMMON)
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_ebss = . ;
} >RAM
PROVIDE ( end = _ebss);
PROVIDE (_end = _ebss);
__exidx_start = .;
__exidx_end = .;
/* after that it's only debugging information. */
/* remove the debugging information from the standard libraries */
/* /DISCARD/ : {
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}*/
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

336
fw/system_stm32f0xx.c Normal file
View file

@ -0,0 +1,336 @@
/**
******************************************************************************
* @file system_stm32f0xx.c
* copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates
* @author MCD Application Team
* @version V2.3.1
* @date 04-November-2016
* @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
*
* 1. This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f0xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
* 2. After each device reset the HSI (8 MHz) is used as system clock source.
* Then SystemInit() function is called, in "startup_stm32f0xx.s" file, to
* configure the system clock before to branch to main program.
*
* 3. This file configures the system clock as follows:
*=============================================================================
* Supported STM32F0xx device
*-----------------------------------------------------------------------------
* System Clock source | HSI
*-----------------------------------------------------------------------------
* SYSCLK(Hz) | 8000000
*-----------------------------------------------------------------------------
* HCLK(Hz) | 8000000
*-----------------------------------------------------------------------------
* AHB Prescaler | 1
*-----------------------------------------------------------------------------
* APB1 Prescaler | 1
*-----------------------------------------------------------------------------
*=============================================================================
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f0xx_system
* @{
*/
/** @addtogroup STM32F0xx_System_Private_Includes
* @{
*/
#include "stm32f0xx.h"
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Defines
* @{
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSI_VALUE */
#if !defined (HSI48_VALUE)
#define HSI48_VALUE ((uint32_t)48000000) /*!< Default value of the HSI48 Internal oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSI48_VALUE */
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock there is no need to
call the 2 first functions listed above, since SystemCoreClock variable is
updated automatically.
*/
uint32_t SystemCoreClock = 8000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system.
* Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001U;
#if defined (STM32F051x8) || defined (STM32F058x8)
/* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
RCC->CFGR &= (uint32_t)0xF8FFB80CU;
#else
/* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */
RCC->CFGR &= (uint32_t)0x08FFB80CU;
#endif /* STM32F051x8 or STM32F058x8 */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFFU;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFFU;
/* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
/* Reset PREDIV[3:0] bits */
RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
#if defined (STM32F072xB) || defined (STM32F078xx)
/* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU;
#elif defined (STM32F071xB)
/* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFFCEACU;
#elif defined (STM32F091xC) || defined (STM32F098xx)
/* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC)
/* Reset USART1SW[1:0], I2C1SW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
#elif defined (STM32F051x8) || defined (STM32F058xx)
/* Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFFFEACU;
#elif defined (STM32F042x6) || defined (STM32F048xx)
/* Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU;
#elif defined (STM32F070x6) || defined (STM32F070xB)
/* Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits */
RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU;
/* Set default USB clock to PLLCLK, since there is no HSI48 */
RCC->CFGR3 |= (uint32_t)0x00000080U;
#else
#warning "No target selected"
#endif
/* Reset HSI14 bit */
RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
/* Disable all interrupts */
RCC->CIR = 0x00000000U;
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f0xx_hal.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f0xx_hal.h file (default value
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @param None
* @retval None
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
{
/* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
}
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV)
{
/* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
}
#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || STM32F091xC || STM32F098xx */
else
{
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
|| defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
|| defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
/* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
SystemCoreClock = (HSI_VALUE/predivfactor) * pllmull;
#else
/* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 ||
STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB ||
STM32F091xC || STM32F098xx || STM32F030xC */
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,30 @@
#!/usr/bin/env python3
import re
import os
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('cmsis_device_header', nargs='+', type=argparse.FileType('rb'))
args = parser.parse_args()
print('#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__')
print('#define __GENERATED_CMSIS_HEADER_EXPORTS__')
print()
for header in args.cmsis_device_header:
lines = header.readlines()
name = os.path.basename(header.name)
print('#include <{}>'.format(name))
print()
print('/* {} */'.format(name))
for l in lines:
match = re.match(b'^#define (\w+)\s+\W*(\w+_TypeDef|\w+_Type).*$', l)
if match:
inst, typedef = match.groups()
inst, typedef = inst.decode(), typedef.decode()
print('{} *{} = {};'.format(typedef, inst.lower(), inst))
print()
print('#endif//__GENERATED_CMSIS_HEADER_EXPORTS__')