stm32f0: SPI and i2c interfaces added

Signed-off-by: Eugene Krashtan <eug.krashtan@gmail.com>
This commit is contained in:
Eugene Krashtan 2019-03-13 17:39:46 +02:00 committed by Kevin O'Connor
parent b79db3e3d6
commit 45f0ea29a6
7 changed files with 274 additions and 1 deletions

View File

@ -7,6 +7,8 @@ config STM32F0_SELECT
default y default y
select HAVE_GPIO select HAVE_GPIO
select HAVE_GPIO_ADC select HAVE_GPIO_ADC
select HAVE_GPIO_I2C
select HAVE_GPIO_SPI
select HAVE_GPIO_BITBANGING select HAVE_GPIO_BITBANGING
config BOARD_DIRECTORY config BOARD_DIRECTORY

View File

@ -26,6 +26,8 @@ src-$(CONFIG_DEBUG_OUT) += stm32f0/log.c
src-$(CONFIG_SERIAL) += stm32f0/serial.c src-$(CONFIG_SERIAL) += stm32f0/serial.c
src-y += generic/serial_irq.c src-y += generic/serial_irq.c
src-$(CONFIG_HAVE_GPIO_ADC) += stm32f0/adc.c src-$(CONFIG_HAVE_GPIO_ADC) += stm32f0/adc.c
src-$(CONFIG_HAVE_GPIO_I2C) += stm32f0/i2c.c
src-$(CONFIG_HAVE_GPIO_SPI) += stm32f0/spi.c
src-y += $(addprefix ../, $(wildcard lib/hal-stm32f0/source/stm32f0xx_*.c)) src-y += $(addprefix ../, $(wildcard lib/hal-stm32f0/source/stm32f0xx_*.c))
src-y += generic/crc16_ccitt.c generic/armcm_irq.c src-y += generic/crc16_ccitt.c generic/armcm_irq.c
src-y += ../lib/cmsis-stm32f0/source/system_stm32f0xx.c src-y += ../lib/cmsis-stm32f0/source/system_stm32f0xx.c

View File

@ -51,6 +51,7 @@ uint8_t const avail_pins[] = {
static uint8_t static uint8_t
gpio_check_pin(uint8_t pin) gpio_check_pin(uint8_t pin)
{ {
gpio_check_busy(pin);
int i; int i;
for(i=0; i<ARRAY_SIZE(avail_pins); i++) { for(i=0; i<ARRAY_SIZE(avail_pins); i++) {
if (avail_pins[i] == pin) if (avail_pins[i] == pin)
@ -139,3 +140,22 @@ void gpio_init(void)
__HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE();
} }
void gpio_check_busy(uint8_t pin)
{
// Increase to uint32_t and assert <32 on bigger chips
static uint16_t pinmap;
assert_param(sizeof(avail_pins)<16);
for (int i = 0; i<sizeof(avail_pins); i++) {
if(avail_pins[i]==pin) {
if(pinmap&(1<<i)) {
break;
} else {
pinmap |= 1<<i;
return;
}
}
}
shutdown("GPIO check failed");
}

55
src/stm32f0/gpio.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef __GENERIC_GPIO_H
#define __GENERIC_GPIO_H
#include <stdint.h> // uint8_t
struct gpio_out {
uint8_t pin;
};
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
void gpio_out_reset(struct gpio_out g, uint8_t val);
void gpio_out_toggle_noirq(struct gpio_out g);
void gpio_out_toggle(struct gpio_out g);
void gpio_out_write(struct gpio_out g, uint8_t val);
struct gpio_in {
uint8_t pin;
};
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
void gpio_in_reset(struct gpio_in g, int8_t pull_up);
uint8_t gpio_in_read(struct gpio_in g);
struct gpio_pwm {
uint8_t pin;
};
struct gpio_pwm gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint8_t val);
void gpio_pwm_write(struct gpio_pwm g, uint8_t val);
struct gpio_adc {
uint8_t pin;
};
struct gpio_adc gpio_adc_setup(uint8_t pin);
uint32_t gpio_adc_sample(struct gpio_adc g);
uint16_t gpio_adc_read(struct gpio_adc g);
void gpio_adc_cancel_sample(struct gpio_adc g);
struct spi_config {
uint32_t cfg;
};
struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate);
void spi_prepare(struct spi_config config);
void spi_transfer(struct spi_config config, uint8_t receive_data
, uint8_t len, uint8_t *data);
struct i2c_config {
uint8_t addr;
};
struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr);
void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write);
void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
, uint8_t read_len, uint8_t *read);
void gpio_check_busy(uint8_t pin);
#endif // gpio.h

88
src/stm32f0/i2c.c Normal file
View File

@ -0,0 +1,88 @@
/*
* i2c support 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 "stm32f0xx_hal.h"
#include "command.h" // shutdown
#include "board/gpio.h" // i2c_setup
#include "sched.h" // sched_shutdown
#include "command.h" // shutdown
I2C_HandleTypeDef hi2c1;
struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/**I2C1 GPIO Configuration
PF0-OSC_IN ------> I2C1_SDA
PF1-OSC_OUT ------> I2C1_SCL
*/
gpio_check_busy(0x30); //PF0
gpio_check_busy(0x31); //PF1
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x2000090E;
hi2c1.Init.OwnAddress1 = addr;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
/** Configure Analogue filter
*/
HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE);
/** Configure Digital filter
*/
HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0);
return (struct i2c_config){ .addr = addr };
}
void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write)
{
while(HAL_I2C_Master_Transmit(&hi2c1, config.addr, write,
(uint16_t)write_len, (uint32_t)1000)!= HAL_OK) {
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
shutdown("Buffer error");
}
}
}
void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
, uint8_t read_len, uint8_t *read)
{
i2c_write(config, reg_len, reg);
while(HAL_I2C_Master_Receive(&hi2c1, config.addr, read,
(uint16_t)read_len, (uint32_t)1000)!= HAL_OK) {
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
shutdown("Buffer error");
}
}
}
/**
* @brief I2C MSP Initialization
* @param hi2c: I2C handle pointer
* @retval None
*/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
if(hi2c->Instance==I2C1)
{
/* Peripheral clock enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_I2C1_CLK_ENABLE();
}
}

106
src/stm32f0/spi.c Normal file
View File

@ -0,0 +1,106 @@
/*
* SPI support on STM32F0 - without HAL for space saving
*
* Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
* This file may be distributed under the terms of the GNU GPLv3 license.
*
*/
#include <string.h> // memcpy
#include "stm32f0xx_hal.h"
#include "command.h" // shutdown
#include "board/gpio.h" // spi_setup
#include "sched.h" // sched_shutdown
#include "log.h"
//static SPI_HandleTypeDef hspi1;
void spi_hw_setup(uint32_t rate)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* SPI1 init - no HAL */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
gpio_check_busy(0x05); //PA5
gpio_check_busy(0x06); //PA6
gpio_check_busy(0x07); //PA7
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
if (rate > 800000) {
SPI1->CR1 = SPI_BAUDRATEPRESCALER_64;
} else {
SPI1->CR1 = SPI_BAUDRATEPRESCALER_256;
}
SPI1->CR1 |= SPI_MODE_MASTER | SPI_DIRECTION_2LINES | SPI_CR1_SSM |
SPI_POLARITY_LOW | SPI_PHASE_1EDGE |
SPI_FIRSTBIT_MSB | SPI_CRCCALCULATION_DISABLE;
SPI1->CR2 = SPI_NSS_PULSE_DISABLE | SPI_DATASIZE_8BIT |
SPI_RXFIFO_THRESHOLD_QF;
SPI1->CR1 |= SPI_CR1_SPE; // Enable
//hspi1.Instance = SPI1;
//hspi1.Init.Mode = SPI_MODE_MASTER;
//hspi1.Init.Direction = SPI_DIRECTION_2LINES;
//hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
//hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
//hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
//hspi1.Init.NSS = SPI_NSS_SOFT;
//hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
//hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
//hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
//hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
//hspi1.Init.CRCPolynomial = 7;
//hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
//hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
//HAL_SPI_Init(&hspi1);
}
struct spi_config
spi_setup(uint32_t bus, uint8_t mode, uint32_t rate)
{
if (bus > 0 || !rate)
shutdown("Invalid spi_setup parameters");
spi_hw_setup(rate);
return (struct spi_config){ .cfg = SPI1->CR1 };
}
void
spi_prepare(struct spi_config config)
{
SPI1->CR1 = config.cfg;
}
void
spi_transfer(struct spi_config config, uint8_t receive_data,
uint8_t len, uint8_t *data)
{
uint8_t rxptr = 0;
while (rxptr<len) {
while(!(SPI1->SR & SPI_SR_TXE));
__DMB();
*((uint8_t*)&(SPI1->DR)) = data[rxptr]; // Hack with pointers
// to write/read only 8 bits from 16-bit DR (see errata)
while(!(SPI1->SR & SPI_SR_RXNE));
__DMB();
if(receive_data) {
data[rxptr] = *((uint8_t*)&(SPI1->DR));
}
rxptr ++;
}
}

View File

@ -63,7 +63,7 @@
/*#define HAL_LPTIM_MODULE_ENABLED */ /*#define HAL_LPTIM_MODULE_ENABLED */
/*#define HAL_RNG_MODULE_ENABLED */ /*#define HAL_RNG_MODULE_ENABLED */
/*#define HAL_RTC_MODULE_ENABLED */ /*#define HAL_RTC_MODULE_ENABLED */
/*#define HAL_SPI_MODULE_ENABLED */ #define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED #define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED #define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */ /*#define HAL_USART_MODULE_ENABLED */