stm32f0: New target STM32F0 added.

Signed-off-by: Eugene Krashtan <Eugene.Krashtan@opensynergy.com>
This commit is contained in:
Eugene Krashtan 2019-03-11 12:47:58 +02:00 committed by Kevin O'Connor
parent 74c6a85cde
commit b822f38923
16 changed files with 1668 additions and 0 deletions

View File

@ -19,6 +19,8 @@ choice
bool "SAMD21/SAMD51"
config MACH_LPC176X
bool "LPC176x (Smoothieboard)"
config MACH_STM32F0
bool "STMicroelectronics STM32F042"
config MACH_STM32F1
bool "STMicroelectronics STM32F103"
config MACH_PRU
@ -33,6 +35,7 @@ source "src/avr/Kconfig"
source "src/atsam/Kconfig"
source "src/atsamd/Kconfig"
source "src/lpc176x/Kconfig"
source "src/stm32f0/Kconfig"
source "src/stm32f1/Kconfig"
source "src/pru/Kconfig"
source "src/linux/Kconfig"

42
src/stm32f0/Kconfig Normal file
View File

@ -0,0 +1,42 @@
# Kconfig settings for STM32F0 processors
if MACH_STM32F0
config STM32F0_SELECT
bool
default y
select HAVE_GPIO
select HAVE_GPIO_ADC
select HAVE_GPIO_BITBANGING
config BOARD_DIRECTORY
string
default "stm32f0"
config CLOCK_FREQ
int
default 48000000
config CANSERIAL
bool "Use CAN bus for communication (instead of serial)"
default y
config SERIAL
depends on !CANSERIAL
bool
default y
config SERIAL_BAUD
int "CAN bus speed" if LOW_LEVEL_OPTIONS && CANSERIAL
default 500000 if CANSERIAL
config DEBUG_OUT
bool "Use debug output to UART TX pin"
depends on CANSERIAL
default y
config USE_LOG
string
default "USE_LOG" if DEBUG_OUT
default "NO_LOG" if !DEBUG_OUT
endif

67
src/stm32f0/Makefile Normal file
View File

@ -0,0 +1,67 @@
# Additional STM32F0 build rules
STLINK=st-flash
# Setup the toolchain
CROSS_PREFIX=arm-none-eabi-
dirs-y += src/stm32f0 src/generic
dirs-y += lib/cmsis-stm32f0/source
dirs-y += lib/hal-stm32f0/source
CFLAGS = -I$(OUT) -Isrc -I$(OUT)board-generic/ -std=gnu11 -O2 -MD \
-Wall -Wold-style-definition $(call cc-option,$(CC),-Wtype-limits,) \
-ffunction-sections -fdata-sections
CFLAGS += -flto -fno-use-linker-plugin
CFLAGS += -mthumb -mcpu=cortex-m0 -g3
CFLAGS += -Ilib/cmsis-core -Iout/board
CFLAGS += -Ilib/cmsis-stm32f0/include -Ilib/cmsis-stm32f0
CFLAGS += -Ilib/hal-stm32f0/include
CFLAGS += -DSTM32F042x6 -DUSE_HAL_DRIVER
# Add source files
src-y += stm32f0/main.c stm32f0/timer.c stm32f0/gpio.c
src-$(CONFIG_CANSERIAL) += stm32f0/can.c
src-$(CONFIG_DEBUG_OUT) += stm32f0/log.c
src-$(CONFIG_SERIAL) += stm32f0/serial.c
src-y += generic/serial_irq.c
src-$(CONFIG_HAVE_GPIO_ADC) += stm32f0/adc.c
src-y += $(addprefix ../, $(wildcard lib/hal-stm32f0/source/stm32f0xx_*.c))
src-y += generic/crc16_ccitt.c generic/armcm_irq.c
src-y += ../lib/cmsis-stm32f0/source/system_stm32f0xx.c
# Add assembler build rules
$(OUT)%.o: %.s $(OUT)autoconf.h $(OUT)board-link
@echo " Assembling $@"
$(Q)$(AS) $< -o $@
asmsrc-y = ../lib/cmsis-stm32f0/source/startup_stm32f042x6.s
OBJS_klipper.elf += $(patsubst %.s, $(OUT)src/%.o,$(asmsrc-y))
# Build the linker script
$(OUT)stm32f0.ld: src/stm32f0/stm32f0.ld $(OUT)board-link
@echo " Preprocessing $@"
$(Q)$(CPP) -P -MD -MT $@ -DFLASH_START=$(CONFIG_FLASH_START) $< -o $@
CFLAGS_klipper.elf += -T $(OUT)stm32f0.ld
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
$(OUT)klipper.elf : $(OUT)stm32f0.ld
# Binary output file rules
target-y += $(OUT)klipper.bin
$(OUT)klipper.bin: $(OUT)klipper.elf
@echo " Creating binary file $@"
$(Q)$(OBJCOPY) -O binary $< $@
$(OUT)klipper.hex: $(OUT)klipper.elf
@echo " Creating hex file $@"
$(Q)$(OBJCOPY) -O ihex $< $@
flash: $(OUT)klipper.hex
@echo " Flashing hex file $<"
$(Q)$(STLINK) --format ihex --reset write $<
debug: $(OUT)klipper.hex
@echo " Remote debug:"
openocd -f interface/stlink.cfg -f target/stm32f0x.cfg

164
src/stm32f0/adc.c Normal file
View File

@ -0,0 +1,164 @@
/*
* ADC functions on STM32F0
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include <stdbool.h> // bool
#include "board/gpio.h" // gpio_adc_setup
#include "board/io.h" // readb
#include "stm32f0xx_hal.h"
#include "internal.h" // GPIO
#include "compiler.h" // ARRAY_SIZE
#include "command.h" // shutdown
#include "sched.h" // sched_shutdown
DECL_CONSTANT("ADC_MAX", 4095);
#define ADC_DELAY (240 * 8)
static bool adc_busy;
static uint8_t adc_current_channel;
ADC_HandleTypeDef hadc;
static const uint8_t adc_pins[] = {
GPIO('A', 0), GPIO('A', 1),
#if !(CONFIG_SERIAL)
GPIO('A', 2), GPIO('A', 3),
#endif
GPIO('A', 4), GPIO('A', 5), GPIO('A', 6), GPIO('A', 7),
GPIO('B', 1),
// Fake ADC on this GPIO (returns tempsensor value)
GPIO('B', 8)
};
static const uint32_t adc_channels[] = {
ADC_CHANNEL_0,
ADC_CHANNEL_1,
#if !(CONFIG_SERIAL)
ADC_CHANNEL_2,
ADC_CHANNEL_3,
#endif
ADC_CHANNEL_4,
ADC_CHANNEL_5,
ADC_CHANNEL_6,
ADC_CHANNEL_7,
ADC_CHANNEL_9,
// For tests
ADC_CHANNEL_TEMPSENSOR
};
struct gpio_adc
gpio_adc_setup(uint8_t pin)
{
// Find pin in adc_pins table
int chan;
ADC_ChannelConfTypeDef sConfig = {0};
for (chan=0; ; chan++) {
if (chan >= ARRAY_SIZE(adc_pins))
shutdown("Not a valid ADC pin");
if (adc_pins[chan] == pin) {
sConfig.Channel = adc_channels[chan];
break;
}
}
/**ADC GPIO Configuration
*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = 1 << (pin % 16);;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init((pin<8)?GPIOA:GPIOB, &GPIO_InitStruct);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
HAL_ADCEx_Calibration_Start(&hadc);
return (struct gpio_adc){ .pin = adc_channels[chan] };
}
// Try to sample a value. Returns zero if sample ready, otherwise
// returns the number of clock ticks the caller should wait before
// retrying this function.
uint32_t
gpio_adc_sample(struct gpio_adc g)
{
/* ADC not busy, start conversion */
if (!readb(&adc_busy)) {
HAL_ADC_Start(&hadc);
adc_busy = true;
adc_current_channel = g.pin;
return ADC_DELAY;
/* ADC finished conversion for this channel */
} else if (HAL_ADC_PollForConversion(&hadc, 100) == HAL_OK) {
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOS);
adc_busy = false;
return 0;
}
/* Wants to sample another channel, or not finished yet */
return ADC_DELAY;
}
// Read a value; use only after gpio_adc_sample() returns zero
uint16_t
gpio_adc_read(struct gpio_adc g)
{
return HAL_ADC_GetValue(&hadc);
}
// Cancel a sample that may have been started with gpio_adc_sample()
void
gpio_adc_cancel_sample(struct gpio_adc g)
{
if (readb(&adc_busy) && readl(&adc_current_channel) == g.pin) {
adc_busy = false;
HAL_ADC_Stop(&hadc);
}
}
/**
* @brief ADC Initialization Function
* @param None
* @retval None
*/
void AdcInit(void)
{
/**Configure the global features of the ADC (Clock,
* Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
HAL_ADC_Init(&hadc);
}
DECL_INIT(AdcInit);
/**
* @brief ADC MSP Initialization
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC1)
{
/* Peripheral clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
}
}

217
src/stm32f0/can.c Normal file
View File

@ -0,0 +1,217 @@
/*
* Serial over CAN emulation for STM32F042 boards.
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include "stm32f0xx_hal.h"
#include <string.h>
#include "can.h"
#include "command.h" // encoder
#include "board/serial_irq.h" // serial_enable_tx_irq
#include "sched.h" // DECL_INIT
#include "log.h"
CAN_HandleTypeDef hcan;
CanTxMsgTypeDef TxMessage;
CanRxMsgTypeDef RxMessage;
static uint16_t MyCanId = 0;
void CanTransmit(uint32_t id, uint32_t dlc, uint8_t *pkt)
{
memcpy(hcan.pTxMsg->Data, pkt, dlc);
hcan.pTxMsg->StdId = id;
hcan.pTxMsg->DLC = dlc;
HAL_CAN_Transmit_IT(&hcan);
}
// Convert Unique 96-bit value into 48 bit representation
static void PackUuid(uint8_t* u)
{
for(int i=0; i<SHORT_UUID_LEN; i++) {
u[i] = *((uint8_t*)(STM32_UUID_ADDR+i)) ^
*((uint8_t*)(STM32_UUID_ADDR+i+SHORT_UUID_LEN));
}
}
static void CanUUIDResp(void)
{
uint8_t short_uuid[SHORT_UUID_LEN];
PackUuid(short_uuid);
CanTransmit(PKT_ID_UUID_RESP, SHORT_UUID_LEN, short_uuid);
}
void CanInit(void)
{
// Master reset
//SET_BIT(CAN->MCR, CAN_MCR_RESET);
hcan.Instance = CAN;
hcan.Init.Prescaler = 12;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SJW = CAN_SJW_1TQ;
hcan.Init.BS1 = CAN_BS1_5TQ;
hcan.Init.BS2 = CAN_BS2_2TQ;
hcan.Init.TTCM = DISABLE;
hcan.Init.ABOM = DISABLE;
hcan.Init.AWUM = DISABLE;
hcan.Init.NART = ENABLE;
hcan.Init.RFLM = DISABLE;
hcan.Init.TXFP = DISABLE;
HAL_CAN_Init(&hcan);
hcan.pTxMsg = &TxMessage;
hcan.pRxMsg = &RxMessage;
/*##-2- Configure the CAN Filter #######################################*/
CAN_FilterConfTypeDef sFilterConfig;
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = PKT_ID_UUID<<5;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = PKT_ID_SET<<5;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
/*##-3- Configure Transmission process #################################*/
hcan.pTxMsg->ExtId = 0;
HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
/* Request for port */
CanUUIDResp();
}
DECL_INIT(CanInit);
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* h) {
int i;
if(!MyCanId) { // If serial not assigned yet
if(h->pRxMsg->StdId == PKT_ID_UUID && h->pRxMsg->DLC == 0) {
// Just inform host about my UUID
CanUUIDResp();
} else if (h->pRxMsg->StdId == PKT_ID_SET) {
// compare my UUID with packet to check if this packet mine
uint8_t short_uuid[SHORT_UUID_LEN];
PackUuid(short_uuid);
if (memcmp(&(h->pRxMsg->Data[2]), short_uuid,
SHORT_UUID_LEN) == 0) {
memcpy(&MyCanId, h->pRxMsg->Data, sizeof(uint16_t));
CAN_FilterConfTypeDef sFilterConfig;
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
// Personal ID
sFilterConfig.FilterIdHigh = MyCanId<<5;
sFilterConfig.FilterIdLow = 0x0000;
// Catch reset command
sFilterConfig.FilterMaskIdHigh = PKT_ID_UUID<<5;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
// Disable 'set address' filter and enable only my packets
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
}
}
} else {
if(h->pRxMsg->StdId == MyCanId) {
if(h->pRxMsg->DLC == 0) {
// empty packet == ping request
hcan.pTxMsg->StdId = MyCanId+1;
hcan.pTxMsg->DLC = 0;
HAL_CAN_Transmit_IT(&hcan);
} else {
for(i=0; i < h->pRxMsg->DLC; i++ ) {
serial_rx_byte(h->pRxMsg->Data[i]);
}
}
} else if (h->pRxMsg->StdId == PKT_ID_UUID && h->pRxMsg->DLC > 0) {
if (memcmp(&(h->pRxMsg->Data), &MyCanId, 2) == 0) {
// Reset from host
NVIC_SystemReset();
}
}
}
HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
}
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *h)
{
// Overrun handling - drop damaged packet
HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
}
/**
* @brief This function handles HDMI-CEC and CAN global interrupts /
* HDMI-CEC wake-up interrupt through EXTI line 27.
*/
void CEC_CAN_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan);
}
void
serial_enable_tx_irq(void)
{
if(MyCanId == 0)
// Serial port not initialized
return;
int i=0;
for (;i<8;)
{
if(serial_get_tx_byte(&(hcan.pTxMsg->Data[i])) == -1) {
break;
}
i++;
}
if (i>0) {
hcan.pTxMsg->StdId = MyCanId+1;
hcan.pTxMsg->DLC = i;
HAL_CAN_Transmit_IT(&hcan);
}
}
void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
{
// if we still have some data to transmit
serial_enable_tx_irq();
}
/*
* @brief CAN MSP Initialization
* @param h: CAN handle pointer
* @retval None
*/
void HAL_CAN_MspInit(CAN_HandleTypeDef* h)
{
__HAL_REMAP_PIN_ENABLE(HAL_REMAP_PA11_PA12);
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(h->Instance==CAN)
{
/* Peripheral clock enable */
__HAL_RCC_CAN1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**CAN GPIO Configuration
PA11 ------> CAN_RX
PA12 ------> CAN_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_CAN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* CAN interrupt Init */
HAL_NVIC_SetPriority(CEC_CAN_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(CEC_CAN_IRQn);
}
}

17
src/stm32f0/can.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef CORE_INC_CAN_H_
#define CORE_INC_CAN_H_
// Read UUID (6bytes)
#define PKT_ID_UUID (0x321)
// Set address (2bytes) to UUID (6b)
#define PKT_ID_SET (0x322)
// UUID response from slave (6bytes)
#define PKT_ID_UUID_RESP (0x323)
#define STM32_UUID_ADDR (0x1FFFF7AC)
#define SHORT_UUID_LEN (6)
void CanInit(void);
void CanTransmit(uint32_t id, uint32_t dlc, uint8_t *pkt);
#endif /* CORE_INC_CAN_H_ */

141
src/stm32f0/gpio.c Normal file
View File

@ -0,0 +1,141 @@
/*
* GPIO functions on STM32F042 boards.
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include "board/gpio.h" // gpio_out_setup
#include "stm32f0xx_hal.h"
#include "internal.h" // GPIO
#include "board/irq.h" // irq_save
#include "compiler.h" // ARRAY_SIZE
#include "sched.h" // sched_shutdown
#include "command.h" // shutdown
DECL_ENUMERATION_RANGE("pin", "PA0", GPIO('A', 0), 11);
DECL_ENUMERATION_RANGE("pin", "PB0", GPIO('B', 0), 9);
DECL_ENUMERATION_RANGE("pin", "PF0", GPIO('F', 0), 2);
GPIO_TypeDef *const digital_regs[] = {
GPIOA, GPIOB, GPIOC, GPIOF
};
// <port:4><pin:4>
uint8_t const avail_pins[] = {
0x0 + 0x0, //PA0
0x0 + 0x1, //PA1
#if !(CONFIG_SERIAL)
0x0 + 0x2, //PA2 - USART pins
0x0 + 0x3, //PA3
#endif
0x0 + 0x4, //PA4
0x0 + 0x5, //PA5
0x0 + 0x6, //PA6
0x0 + 0x7, //PA7
#if !(CONFIG_CANSERIAL)
0x0 + 0x9, //PA9 - but remapped in CAN mode to PA11,PA12
0x0 + 0xa, //PA10
#endif
0x10 + 0x1, //PB1
0x10 + 0x8, //PB8
0x50 + 0x0, //PF0
0x50 + 0x1, //PF1
};
/****************************************************************
* General Purpose Input Output (GPIO) pins
****************************************************************/
static uint8_t
gpio_check_pin(uint8_t pin)
{
int i;
for(i=0; i<ARRAY_SIZE(avail_pins); i++) {
if (avail_pins[i] == pin)
return i;
}
return 0xFF;
}
struct gpio_out
gpio_out_setup(uint8_t pin, uint8_t val)
{
struct gpio_out g = { .pin=pin };
if (gpio_check_pin(pin) < 0xFF) {
gpio_out_reset(g, val);
} else {
shutdown("Not an output pin");
}
return g;
}
void
gpio_out_reset(struct gpio_out g, uint8_t val)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = 1 << (g.pin % 16);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(digital_regs[GPIO2PORT(g.pin)], &GPIO_InitStruct);
HAL_GPIO_WritePin(digital_regs[GPIO2PORT(g.pin)], 1 << (g.pin % 16), val);
}
void
gpio_out_write(struct gpio_out g, uint8_t val)
{
HAL_GPIO_WritePin(digital_regs[GPIO2PORT(g.pin)], 1 << (g.pin % 16), val);
}
struct gpio_in
gpio_in_setup(uint8_t pin, int8_t pull_up)
{
struct gpio_in g = { .pin=pin };
if (gpio_check_pin(pin) < 0xFF) {
gpio_in_reset(g, pull_up);
} else {
shutdown("Not an input pin");
}
return g;
}
void
gpio_in_reset(struct gpio_in g, int8_t pull_up)
{
irqstatus_t flag = irq_save();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = 1 << (g.pin % 16);
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = (pull_up)?GPIO_PULLUP:GPIO_NOPULL;
HAL_GPIO_Init(digital_regs[GPIO2PORT(g.pin)], &GPIO_InitStruct);
irq_restore(flag);
}
uint8_t
gpio_in_read(struct gpio_in g)
{
return HAL_GPIO_ReadPin(digital_regs[GPIO2PORT(g.pin)], 1 << (g.pin % 16));
}
void
gpio_out_toggle_noirq(struct gpio_out g)
{
HAL_GPIO_TogglePin(digital_regs[GPIO2PORT(g.pin)], 1 << (g.pin % 16));
}
void
gpio_out_toggle(struct gpio_out g)
{
irqstatus_t flag = irq_save();
gpio_out_toggle_noirq(g);
irq_restore(flag);
}
void gpio_init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
}

16
src/stm32f0/internal.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __STM32F0_INTERNAL_H
#define __STM32F0_INTERNAL_H
// Local definitions for STM32F0 code
#include "stm32f0xx.h"
#define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM))
#define GPIO2PORT(PIN) ((PIN) / 16)
extern uint8_t const avail_pins[];
void udelay(uint32_t usecs);
void gpio_init(void);
void TimerInit(void);
#endif // internal.h

79
src/stm32f0/log.c Normal file
View File

@ -0,0 +1,79 @@
/*
* log.c
* This file not required for regular Klipper usage, but hw/sw developer
* can use USART TX pin instead SWO for debugging purposes
*
* Created on: Jan 17, 2019
* Author: eug
*/
#include "string.h"
#include "stm32f0xx_hal.h"
#include "log.h"
UART_HandleTypeDef huart2;
void LogInit(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
lprint("hello");
}
/**
* @brief String out
* @param msg: Null-terminated string
* @retval None
*/
void lprint(char *msg)
{
HAL_UART_Transmit(&huart2, (uint8_t *)msg, strlen(msg), 100);
}
/**
* @brief Binary data out
* @param msg: binary data
* @param len: data length
* @retval None
*/
void lnprint(char *msg, size_t len)
{
HAL_UART_Transmit(&huart2, (uint8_t *)msg, len, 100);
}
/**
* @brief UART MSP Initialization
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART2)
{
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}

18
src/stm32f0/log.h Normal file
View File

@ -0,0 +1,18 @@
/*
* log.h
*
* Created on: Jan 17, 2019
* Author: eug
*/
#ifndef CORE_INC_LOG_H_
#define CORE_INC_LOG_H_
void LogInit(void);
void lprint(char *msg);
void lnprint(char *msg, size_t len);
#endif /* CORE_INC_LOG_H_ */

201
src/stm32f0/main.c Normal file
View File

@ -0,0 +1,201 @@
/*
* Main starting point for STM32F042 boards.
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include "stm32f0xx_hal.h"
#include "autoconf.h"
#include "command.h" // DECL_CONSTANT
#include "board/misc.h" // timer_read_time
#include "sched.h" // sched_main
#include "internal.h"
#include "can.h"
#include "log.h"
DECL_CONSTANT_STR("MCU","stm32f042");
static IWDG_HandleTypeDef hiwdg;
/****************************************************************
* dynamic memory pool
****************************************************************/
static char dynmem_pool[3 * 1024];
// Return the start of memory available for dynamic allocations
void *
dynmem_start(void)
{
return dynmem_pool;
}
// Return the end of memory available for dynamic allocations
void *
dynmem_end(void)
{
return &dynmem_pool[sizeof(dynmem_pool)];
}
/****************************************************************
* misc functions
****************************************************************/
void
command_reset(uint32_t *args)
{
NVIC_SystemReset();
}
DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
void clock_config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI
|RCC_OSCILLATORTYPE_HSI14|RCC_OSCILLATORTYPE_HSI48
|RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.HSI14CalibrationValue = 16;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_RTC;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
}
// Implement simple early-boot delay mechanism
void
udelay(uint32_t usecs)
{
uint32_t end = timer_read_time() + timer_from_us(usecs);
while (timer_is_before(timer_read_time(), end))
;
}
void
watchdog_reset(void)
{
HAL_IWDG_Refresh(&hiwdg);
}
DECL_TASK(watchdog_reset);
void
watchdog_init(void)
{
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_16;
hiwdg.Init.Window = 4095;
hiwdg.Init.Reload = 4095;
//HAL_IWDG_Init(&hiwdg); ToDo enable after debug
}
DECL_INIT(watchdog_init);
// Main entry point
int
main(void)
{
HAL_Init();
clock_config();
gpio_init();
#if (CONFIG_DEBUG_OUT)
LogInit();
#endif
sched_main();
return 0;
}
void __attribute__((weak)) lprint(char *msg) {}
void __attribute__((weak)) lnprint(char *msg, size_t len) {}
/*
* MSP init functions ( __weak replacement )
*/
/*
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_RCC_WWDG_CLK_ENABLE();
}
/****************************************************************
* Debug helper (taken from https://community.arm.com/)
* In case of Hard Fault it helps to find fault reason
* on Cortex-M0 chips
****************************************************************/
void hard_fault_handler_c(unsigned long *hardfault_args){
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
volatile unsigned long stacked_r0 ;
volatile unsigned long stacked_r1 ;
volatile unsigned long stacked_r2 ;
volatile unsigned long stacked_r3 ;
volatile unsigned long stacked_r12 ;
volatile unsigned long stacked_lr ;
volatile unsigned long stacked_pc ;
volatile unsigned long stacked_psr ;
volatile unsigned long _CFSR ;
volatile unsigned long _HFSR ;
volatile unsigned long _DFSR ;
volatile unsigned long _AFSR ;
volatile unsigned long _BFAR ;
volatile unsigned long _MMAR ;
stacked_r0 = ((unsigned long)hardfault_args[0]) ;
stacked_r1 = ((unsigned long)hardfault_args[1]) ;
stacked_r2 = ((unsigned long)hardfault_args[2]) ;
stacked_r3 = ((unsigned long)hardfault_args[3]) ;
stacked_r12 = ((unsigned long)hardfault_args[4]) ;
stacked_lr = ((unsigned long)hardfault_args[5]) ;
stacked_pc = ((unsigned long)hardfault_args[6]) ;
stacked_psr = ((unsigned long)hardfault_args[7]) ;
// Configurable Fault Status Register
// Consists of MMSR, BFSR and UFSR
_CFSR = (*((volatile unsigned long *)(0xE000ED28))) ;
// Hard Fault Status Register
_HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ;
// Debug Fault Status Register
_DFSR = (*((volatile unsigned long *)(0xE000ED30))) ;
// Auxiliary Fault Status Register
_AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ;
// Read the Fault Address Registers. These may not contain valid values.
// Check BFARVALID/MMARVALID to see if they are valid values
// MemManage Fault Address Register
_MMAR = (*((volatile unsigned long *)(0xE000ED34))) ;
// Bus Fault Address Register
_BFAR = (*((volatile unsigned long *)(0xE000ED38))) ;
__asm("BKPT #0\n") ; // Break into the debugger
#pragma GCC diagnostic pop
}

98
src/stm32f0/serial.c Normal file
View File

@ -0,0 +1,98 @@
/*
* Serial communication for STM32F042 boards.
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include "stm32f0xx_hal.h"
#include <string.h>
#include "autoconf.h" // CONFIG_SERIAL_BAUD
#include "board/serial_irq.h" // serial_rx_byte
#include "sched.h" // DECL_INIT
UART_HandleTypeDef huart2;
static uint8_t rxbuf, txbuf;
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart2);
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
void UartInit(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = CONFIG_SERIAL_BAUD;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
HAL_UART_Receive_IT(&huart2,&rxbuf,(uint16_t)1);
}
DECL_INIT(UartInit);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart2) {
serial_rx_byte(rxbuf);
HAL_UART_Receive_IT(&huart2,&rxbuf,(uint16_t)1);
}
}
void serial_enable_tx_irq(void)
{
while(huart2.gState != HAL_UART_STATE_READY);
if(serial_get_tx_byte(&txbuf) == 0) {
HAL_UART_Transmit_IT(&huart2,&txbuf,(uint16_t)1);
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart2)
serial_enable_tx_irq();
}
/**
* @brief UART MSP Initialization
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART2)
{
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART2 interrupt Init */
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
}

111
src/stm32f0/stm32f0.ld Normal file
View File

@ -0,0 +1,111 @@
/* Linker script for STM32F042F6Px Device with 32KByte FLASH, 6KByte RAM
This file is taken from lib/cmsis-stm32f0/source/STM32F042F6Px_FLASH.ld
*/
ENTRY(Reset_Handler)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
}
/* highest address of the user mode stack */
_estack = 0x20001800;
SECTIONS
{
/* Interrupt vector table */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector))
. = ALIGN(4);
} >FLASH
/* Program code and constant data */
.text :
{
. = ALIGN(4);
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .;
} >FLASH
/* Exception handling */
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
/* Static constructor initialization (C++) */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* Initialized data, needs to be handled by startup code */
_sidata = .;
.data : AT (_sidata)
{
. = ALIGN(4);
_sdata = . ;
_data = . ;
*(.data)
*(.data*)
*(.RAMtext)
. = ALIGN(4);
_edata = . ;
} >RAM
/* Uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = .;
__bss_start__ = .;
_bss = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
__bss_end__ = _ebss;
} >RAM
/* Pointers to end of data for dynamic memory management */
PROVIDE (end = _ebss);
PROVIDE (_end = _ebss);
/* Remove debugging from standard libraries */
/DISCARD/ :
{
libc.a (*)
libm.a (*)
libgcc.a (*)
}
}

View File

@ -0,0 +1,336 @@
/**
******************************************************************************
* @file stm32f0xx_hal_conf.h
* @brief HAL configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2019 STMicroelectronics</center></h2>
*
*Redistribution 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -----------------------------------*/
#ifndef __STM32F0xx_HAL_CONF_H
#define __STM32F0xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ----------------------------------------------------------*/
/* Exported constants ------------------------------------------------------*/
/* ########################## Module Selection ############################ */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
/*#define HAL_CRYP_MODULE_ENABLED */
#define HAL_CAN_MODULE_ENABLED
/*#define HAL_CEC_MODULE_ENABLED */
/*#define HAL_COMP_MODULE_ENABLED */
/*#define HAL_CRC_MODULE_ENABLED */
/*#define HAL_CRYP_MODULE_ENABLED */
/*#define HAL_TSC_MODULE_ENABLED */
/*#define HAL_DAC_MODULE_ENABLED */
/*#define HAL_I2S_MODULE_ENABLED */
#define HAL_IWDG_MODULE_ENABLED
/*#define HAL_LCD_MODULE_ENABLED */
/*#define HAL_LPTIM_MODULE_ENABLED */
/*#define HAL_RNG_MODULE_ENABLED */
/*#define HAL_RTC_MODULE_ENABLED */
/*#define HAL_SPI_MODULE_ENABLED */
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */
/*#define HAL_SMARTCARD_MODULE_ENABLED */
/*#define HAL_SMBUS_MODULE_ENABLED */
/*#define HAL_WWDG_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
/*#define HAL_EXTI_MODULE_ENABLED */
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
/* ########################## HSE/HSI Values adaptation ################### */
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used\
* in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
/*!< Value of the External oscillator in Hz */
#define HSE_VALUE ((uint32_t)8000000)
#endif /* HSE_VALUE */
/**
* @brief In the following line adjust the External High Speed oscillator\
* (HSE) Startup
* Timeout value
*/
#if !defined (HSE_STARTUP_TIMEOUT)
/*!< Time out for HSE start up, in ms */
#define HSE_STARTUP_TIMEOUT ((uint32_t)100)
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
/*!< Value of the Internal oscillator in Hz*/
#define HSI_VALUE ((uint32_t)8000000)
#endif /* HSI_VALUE */
/**
* @brief In the following line adjust the Internal High Speed oscillator \
* (HSI) Startup
* Timeout value
*/
#if !defined (HSI_STARTUP_TIMEOUT)
#define HSI_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSI startup */
#endif /* HSI_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator for ADC (HSI14) value.
*/
#if !defined (HSI14_VALUE)
#define HSI14_VALUE ((uint32_t)14000000)
/*!< Value of the Internal High Speed oscillator for ADC in Hz.
The real value may vary depending on the variations
in voltage and temperature. */
#endif /* HSI14_VALUE */
/**
* @brief Internal High Speed oscillator for USB (HSI48) value.
*/
#if !defined (HSI48_VALUE)
#define HSI48_VALUE ((uint32_t)48000000)
/*!< Value of the Internal High Speed oscillator for USB in Hz.
The real value may vary depending on the variations
in voltage and temperature. */
#endif /* HSI48_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE ((uint32_t)40000)
#endif /* LSI_VALUE */
/*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSI) value.
*/
#if !defined (LSE_VALUE)
/*!< Value of the External Low Speed oscillator in Hz */
#define LSE_VALUE ((uint32_t)32768)
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
/*!< Time out for LSE start up, in ms */
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000)
#endif /* LSE_STARTUP_TIMEOUT */
/* Tip: To avoid modifying this file each time you need to use different HSE,
you can define the HSE value in your toolchain compiler preprocessor. */
/* ######################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
/*!< tick interrupt priority (lowest by default) */
#define TICK_INT_PRIORITY ((uint32_t)0)
/* Warning: Must be set to higher priority for HAL_Delay() */
/* and HAL_GetTick() usage under interrupt context */
#define USE_RTOS 0
#define PREFETCH_ENABLE 1
#define INSTRUCTION_CACHE_ENABLE 0
#define DATA_CACHE_ENABLE 0
/* ########################## Assert Selection ############################# */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* ################## SPI peripheral configuration ######################### */
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
* Activated: CRC code is present inside driver
* Deactivated: CRC code cleaned from driver
*/
#define USE_SPI_CRC 0U
/* Includes -----------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f0xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32f0xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32f0xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32f0xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f0xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32f0xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_CAN_MODULE_ENABLED
#include "stm32f0xx_hal_can.h"
#endif /* HAL_CAN_MODULE_ENABLED */
#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32f0xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */
#ifdef HAL_COMP_MODULE_ENABLED
#include "stm32f0xx_hal_comp.h"
#endif /* HAL_COMP_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32f0xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32f0xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32f0xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32f0xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32f0xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32f0xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32f0xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32f0xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32f0xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32f0xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32f0xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32f0xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32f0xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32f0xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_TSC_MODULE_ENABLED
#include "stm32f0xx_hal_tsc.h"
#endif /* HAL_TSC_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32f0xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32f0xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32f0xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
/* Exported macro -----------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) \
((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------ */
void assert_failed(char* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F0xx_HAL_CONF_H */
/********************** (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

156
src/stm32f0/timer.c Normal file
View File

@ -0,0 +1,156 @@
/*
* Timer and PWM functions for STM32F042 boards.
* Also replacement for 'generic/armcm_timer.c', which not compatible
* with Cortex-M0 CPUs
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
* DO NOT USE HAL! (Timer HAL extremely fat)
*/
#include "autoconf.h" // CONFIG_CLOCK_FREQ
#include "board/internal.h" // SysTick
#include "board/irq.h" // irq_disable
#include "stm32f0xx.h"
#include "log.h"
#include "sched.h" // DECL_INIT
#include "command.h" // shutdown
DECL_CONSTANT("CLOCK_FREQ", CONFIG_CLOCK_FREQ);
// Return the number of clock ticks for a given number of microseconds
uint32_t
timer_from_us(uint32_t us)
{
return us * (CONFIG_CLOCK_FREQ / 1000000);
}
// Return true if time1 is before time2. Always use this function to
// compare times as regular C comparisons can fail if the counter
// rolls over.
uint8_t
timer_is_before(uint32_t time1, uint32_t time2)
{
return (int32_t)(time1 - time2) < 0;
}
// Set the next irq time
static void
timer_set_diff(uint32_t value)
{
SysTick->LOAD = value;
SysTick->VAL = 0;
SysTick->LOAD = 0;
}
// Activate timer dispatch as soon as possible
void
timer_kick(void)
{
SysTick->LOAD = 0;
SysTick->VAL = 0;
SCB->ICSR = SCB_ICSR_PENDSTSET_Msk;
}
/*
* TIM2 (32bit) used instead of DWT->CYCCNT in original variant
*/
void TimerInit(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 0;
//TIM2->ARR = 0xFFFFFFFF; reset value
TIM2->DIER = TIM_DIER_UIE;
TIM2->CR1 = TIM_CR1_CEN;
NVIC_EnableIRQ(TIM2_IRQn);
// Enable SysTick
irqstatus_t flag = irq_save();
NVIC_SetPriority(SysTick_IRQn, 2);
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk
| SysTick_CTRL_ENABLE_Msk);
timer_kick();
irq_restore(flag);
}
DECL_INIT(TimerInit);
uint32_t
timer_read_time(void)
{
return TIM2->CNT;
}
static uint32_t timer_repeat_until;
#define TIMER_IDLE_REPEAT_TICKS timer_from_us(500)
#define TIMER_REPEAT_TICKS timer_from_us(100)
#define TIMER_MIN_TRY_TICKS timer_from_us(2)
#define TIMER_DEFER_REPEAT_TICKS timer_from_us(5)
// Invoke timers
static uint32_t
timer_dispatch_many(void)
{
uint32_t tru = timer_repeat_until;
for (;;) {
// Run the next software timer
uint32_t next = sched_timer_dispatch();
uint32_t now = timer_read_time();
int32_t diff = next - now;
if (diff > (int32_t)TIMER_MIN_TRY_TICKS)
// Schedule next timer normally.
return diff;
if (unlikely(timer_is_before(tru, now))) {
// Check if there are too many repeat timers
if (diff < (int32_t)(-timer_from_us(1000)))
try_shutdown("Rescheduled timer in the past");
if (sched_tasks_busy()) {
timer_repeat_until = now + TIMER_REPEAT_TICKS;
return TIMER_DEFER_REPEAT_TICKS;
}
timer_repeat_until = tru = now + TIMER_IDLE_REPEAT_TICKS;
}
// Next timer in the past or near future - wait for it to be ready
irq_enable();
while (unlikely(diff > 0))
diff = next - timer_read_time();
irq_disable();
}
}
// IRQ handler
void __visible __aligned(16) // aligning helps stabilize perf benchmarks
SysTick_Handler(void)
{
irq_disable();
uint32_t diff = timer_dispatch_many();
timer_set_diff(diff);
irq_enable();
}
// Make sure timer_repeat_until doesn't wrap 32bit comparisons
void
timer_task(void)
{
uint32_t now = timer_read_time();
irq_disable();
if (timer_is_before(timer_repeat_until, now))
timer_repeat_until = now;
irq_enable();
}
DECL_TASK(timer_task);
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF) {
TIM2->SR &= ~TIM_SR_UIF; // clear UIF flag
}
}

View File

@ -0,0 +1,2 @@
# Base config file for STM32F0 ARM processor
CONFIG_MACH_STM32F0=y