Initial fw commit
This commit is contained in:
parent
0e25682ed7
commit
226fef1618
17 changed files with 4845 additions and 0 deletions
11
fw/.gitignore
vendored
Normal file
11
fw/.gitignore
vendored
Normal 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
104
fw/Makefile
Normal 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
2615
fw/Scope.ipynb
Normal file
File diff suppressed because one or more lines are too long
25
fw/base.c
Normal file
25
fw/base.c
Normal 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
48
fw/cmsis_exports.c
Normal 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
65
fw/global.h
Normal 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
236
fw/i2c.c
Normal 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
107
fw/i2c.h
Normal 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
97
fw/main.c
Normal 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
244
fw/mpu6050.c
Normal 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
491
fw/mpu6050.h
Normal 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
15
fw/openocd.cfg
Normal 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
12
fw/scope.gdb
Normal 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
273
fw/startup_stm32f030x6.s
Normal 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
136
fw/stm32_flash.ld
Normal 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
336
fw/system_stm32f0xx.c
Normal 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>© 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****/
|
||||
|
||||
30
fw/tools/gen_cmsis_exports.py
Normal file
30
fw/tools/gen_cmsis_exports.py
Normal 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__')
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue