3 Commits

Author SHA1 Message Date
Christopher Anderson
5e51e0b8e3 SPI rework for Dartuino and STM32F7. Still needs some soak testing. 2016-03-10 01:19:09 -08:00
Christopher Anderson
945308fe03 [dartuino] provide feedback on memory lcd failure 2016-03-10 01:16:54 -08:00
Christopher Anderson
11fd254c58 [scripts] Update stm32f7 discovery script to use the upstread openocd stm32f7discovery.cfg 2016-03-10 01:16:54 -08:00
9 changed files with 355 additions and 29 deletions

View File

@@ -0,0 +1,17 @@
#pragma once
#include <err.h>
#include <platform/stm32.h>
#include <kernel/mutex.h>
struct spi_bus {
SPI_TypeDef *spi;
mutex_t lock;
};
#define INVALID_SPI_BUS -1
status_t spi_init (SPI_HandleTypeDef *handle);
status_t spi_write(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs);
status_t spi_read(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs);
status_t spi_transaction(SPI_HandleTypeDef *handle, uint8_t *wdata, uint8_t *rdata, size_t len, uint32_t cs);

View File

@@ -48,11 +48,12 @@ MODULE_SRCS += \
$(LOCAL_DIR)/usbc.c \
$(LOCAL_DIR)/vectab.c \
$(LOCAL_DIR)/sdram.c \
$(LOCAL_DIR)/spi.c \
$(LOCAL_DIR)/qspi.c
# use a two segment memory layout, where all of the read-only sections
# of the binary reside in rom, and the read/write are in memory. The
# ROMBASE, MEMBASE, and MEMSIZE make variables are required to be set
# use a two segment memory layout, where all of the read-only sections
# of the binary reside in rom, and the read/write are in memory. The
# ROMBASE, MEMBASE, and MEMSIZE make variables are required to be set
# for the linker script to be generated properly.
#
LINKER_SCRIPT += \

312
platform/stm32f7xx/spi.c Normal file
View File

@@ -0,0 +1,312 @@
#include <assert.h>
#include <debug.h>
#include <stdlib.h>
#include <string.h>
#include <target/gpioconfig.h>
#include <platform/spi.h>
#include <platform/stm32.h>
static struct spi_bus spi_busses[] = {
{ .spi = SPI1 },
{ .spi = SPI2 },
{ .spi = SPI3 },
{ .spi = SPI4 },
{ .spi = SPI5 },
{ .spi = SPI6 }
};
static inline int get_bus_idx(SPI_TypeDef *spi)
{
for (unsigned int i = 0; i < (sizeof(spi_busses)/sizeof(spi_busses[0])); i++) {
if (spi_busses[i].spi == spi) {
return i;
}
}
return INVALID_SPI_BUS;
}
static bool wait_for_bus_ready(SPI_HandleTypeDef *handle)
{
size_t timeout = 1024;
while (timeout && (HAL_SPI_GetState(handle) != HAL_SPI_STATE_READY)) {
timeout--;
}
if (timeout == 0) {
return false;
}
return true;
}
status_t spi_init (SPI_HandleTypeDef *handle)
{
DEBUG_ASSERT(handle);
status_t ret = NO_ERROR;
int bus = get_bus_idx(handle->Instance);
if (bus == INVALID_SPI_BUS) {
return ERR_NOT_FOUND;
}
mutex_init(&(spi_busses[bus].lock));
if (HAL_SPI_Init(handle) != HAL_OK) {
ret = ERR_GENERIC;
}
return ret;
}
status_t spi_write(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs)
{
DEBUG_ASSERT(handle);
DEBUG_ASSERT(data);
DEBUG_ASSERT(len);
status_t ret = NO_ERROR;
int bus = get_bus_idx(handle->Instance);
if (bus == INVALID_SPI_BUS) {
return ERR_NOT_FOUND;
}
mutex_acquire(&(spi_busses[bus].lock));
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_RESET : GPIO_PIN_SET);
}
HAL_StatusTypeDef foo;
/* The lock may have been released while the hardware is still processing a transaction */
/*if (!wait_for_bus_ready(handle)) {
ret = ERR_BUSY;
} else {*/
if ((foo = HAL_SPI_Transmit(handle, data, len, HAL_MAX_DELAY)) != HAL_OK) {
printf("foo %d\n", foo);
ret = ERR_IO;
}
// }
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
mutex_release(&(spi_busses[bus].lock));
return ret;
}
status_t spi_read(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs)
{
DEBUG_ASSERT(handle);
DEBUG_ASSERT(data);
DEBUG_ASSERT(len);
status_t ret = NO_ERROR;
int bus = get_bus_idx(handle->Instance);
if (bus == INVALID_SPI_BUS) {
return ERR_NOT_FOUND;
}
mutex_acquire(&(spi_busses[bus].lock));
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_RESET : GPIO_PIN_SET);
}
if (HAL_SPI_Receive(handle, data, len, HAL_MAX_DELAY) != HAL_OK) {
ret = ERR_IO;
}
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
mutex_release(&(spi_busses[bus].lock));
return ret;
}
status_t spi_transaction(SPI_HandleTypeDef *handle, uint8_t *wdata, uint8_t *rdata, size_t len, uint32_t cs)
{
DEBUG_ASSERT(handle);
DEBUG_ASSERT(wdata);
DEBUG_ASSERT(rdata);
DEBUG_ASSERT(len);
status_t ret = NO_ERROR;
int bus = get_bus_idx(handle->Instance);
if (bus == INVALID_SPI_BUS) {
return ERR_NOT_FOUND;
}
mutex_acquire(&(spi_busses[bus].lock));
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_RESET : GPIO_PIN_SET);
}
if (HAL_SPI_TransmitReceive(handle, wdata, rdata, len, HAL_MAX_DELAY) != HAL_OK) {
ret = ERR_IO;
}
if (handle->Init.NSS == SPI_NSS_SOFT) {
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
mutex_release(&(spi_busses[bus].lock));
return ret;
}
#if WITH_LIB_CONSOLE
#include <lib/console.h>
/* Bus configurations for testing. Although it requires a recompilation per setting tweaked,
* it saves us from having to write a great deal of configuration code via an awkward console
* interface with many arguments.
*
* XXX: This doesn't handle soft NSS on its own.
*/
// This test code is primarily for DartuinoP0 and the GPIO will only exist for that target
#define STM32F7_SPI_BUS_CNT 6
static SPI_HandleTypeDef handles[STM32F7_SPI_BUS_CNT] = {
[0] = { 0 },
[1] = {
.Instance = SPI2,
.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4,
.Init.Direction = SPI_DIRECTION_1LINE,
.Init.CLKPhase = SPI_PHASE_1EDGE,
.Init.CLKPolarity = SPI_POLARITY_LOW,
.Init.DataSize = SPI_DATASIZE_8BIT,
.Init.FirstBit = SPI_FIRSTBIT_LSB,
.Init.TIMode = SPI_TIMODE_DISABLE,
.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
.Init.CRCPolynomial = 7,
.Init.NSS = SPI_NSS_SOFT,
.Init.Mode = SPI_MODE_MASTER,
},
[2] = { 0 },
[3] = { 0 },
[4] = { 0 },
[5] = {
.Instance = SPI5,
.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4,
.Init.Direction = SPI_DIRECTION_1LINE,
.Init.CLKPhase = SPI_PHASE_1EDGE,
.Init.CLKPolarity = SPI_POLARITY_LOW,
.Init.DataSize = SPI_DATASIZE_8BIT,
.Init.FirstBit = SPI_FIRSTBIT_MSB,
.Init.TIMode = SPI_TIMODE_DISABLE,
.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
.Init.CRCPolynomial = 7,
.Init.NSS = SPI_NSS_SOFT,
.Init.Mode = SPI_MODE_MASTER,
},
};
// GPIO to whack for soft chip select
static unsigned int handle_nss[STM32F7_SPI_BUS_CNT] = {
[5] = GPIO(GPIO_PORT_K, 0), // NRF_CS on Dartuino P0
};
/* Check if bus is valid, initialize it if needed */
static inline bool check_bus(uint8_t bus)
{
if (bus < STM32F7_SPI_BUS_CNT && handles[bus].Instance == 0) {
return false;
}
if (HAL_SPI_GetState(&handles[bus]) == HAL_SPI_STATE_RESET) {
HAL_SPI_Init(&handles[bus]);
}
return true;
}
static void print_spi_usage(void)
{
printf("spi read <bus> <len>\n");
printf("\tRead <len> bytes from <bus>\n");
printf("spi spew <bus> <len> <n> <delay>\n");
printf("\tWrite <len> bytes <n> times with a delay of <delay> ms between over <bus>\n");
}
#define IS_CMD(_str, _argc) (argc >= _argc && (strcmp(_str, argv[1].str) == 0))
static int cmd_spi(int argc, const cmd_args *argv)
{
status_t ret = NO_ERROR;
// spi read <bus> <len>
if (IS_CMD("read", 4)) {
uint8_t bus = argv[2].i;
size_t len = MIN(1024, argv[3].i);
uint8_t *data = (uint8_t *)malloc(len);
if (!data) {
ret = ERR_NO_MEMORY;
goto read_err;
}
if (!check_bus(bus)) {
printf("Error: bus %u is invalid\n", bus);
ret = ERR_INVALID_ARGS;
goto read_err;
}
if (spi_read(&handles[bus], data, len, handle_nss[bus]) != NO_ERROR) {
printf("spi read error\n");
ret = ERR_IO;
goto read_err;
}
hexdump8(data, len);
read_err:
free(data);
// spi spew <bus> <len> <iterations> <delay>
} else if (IS_CMD("spew", 6)) {
uint8_t bus = argv[2].i;
size_t len = MIN(1024, argv[3].i);
uint32_t cnt = argv[4].i;
uint32_t delay = argv[5].i;
uint8_t *data = (uint8_t *)malloc(len);
if (cnt == 0) {
cnt = UINT32_MAX;
}
for (uint32_t i = 0; i < len; i++) {
data[i] = i % 255;
}
for (uint32_t i = 0; i < cnt; i++) {
int spi_ret;
if ((spi_ret = spi_write(&handles[bus], data, len, handle_nss[bus])) != NO_ERROR) {
printf("spi write error: %d\n", spi_ret);
ret = ERR_IO;
goto spew_err;
}
if (delay > 0) {
thread_sleep(delay);
}
}
spew_err:
free(data);
} else {
print_spi_usage();
}
return ret;
}
STATIC_COMMAND_START
STATIC_COMMAND("spi", "spi commands for stm32f7", &cmd_spi)
STATIC_COMMAND_END(spi);
#endif // WITH_LIB_CONSOLE

View File

@@ -3,5 +3,5 @@
export PROJECT=dartuinoP0-test
make -j8 &&
openocd -f interface/stlink-v2.cfg -f board/stm32756g_eval.cfg \
openocd -f interface/stlink-v2.cfg -f target/stm32f7x.cfg \
-c "program build-$PROJECT/lk.bin reset exit 0x08000000"

View File

@@ -3,5 +3,5 @@
export PROJECT=stm32f746g-disco-test
make -j8 &&
openocd -f interface/stlink-v2-1.cfg -f board/stm32756g_eval.cfg \
openocd -f interface/stlink-v2-1.cfg -f board/stm32f7discovery.cfg \
-c "program build-$PROJECT/lk.bin reset exit 0x08000000"

View File

@@ -132,7 +132,9 @@ void target_init(void)
qspi_flash_init(N25Q128A_FLASH_SIZE);
memory_lcd_init();
if (memory_lcd_init() != NO_ERROR) {
printf("error initializing memory_lcd\n");
}
#if WITH_LIB_MINIP
uint8_t mac_addr[6];
@@ -207,6 +209,19 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
/*##-3- Configure the NVIC for SPI #########################################*/
/* NVIC for SPI */
HAL_NVIC_EnableIRQ(SPI2_IRQn);
} else if (hspi->Instance == SPI5) {
/* SPI5
* PF6 SPI5_NSS
* PF7 SPI5_SCK
* PF8 SPI5_MISO
* PF9 SPI5_MOSI
*/
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_SPI5_CLK_ENABLE();
gpio_config(GPIO_SPI5_SCK, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
gpio_config(GPIO_SPI5_MISO, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
gpio_config(GPIO_SPI5_MOSI, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
HAL_NVIC_EnableIRQ(SPI5_IRQn);
}
}

View File

@@ -9,7 +9,7 @@ PLATFORM := stm32f7xx
SDRAM_SIZE := 0x00800000
SDRAM_BASE := 0xc0000000
DISPLAY_PANEL_TYPE ?= LS013B7DH06
DISPLAY_PANEL_TYPE ?= LS027B7DH01
GLOBAL_DEFINES += \
ENABLE_UART3=1 \

View File

@@ -23,12 +23,12 @@
#include <err.h>
#include <kernel/mutex.h>
#include <platform/gpio.h>
#include <platform/spi.h>
#include <target/gpioconfig.h>
#include <target/bmi055.h>
#include <target/sensor_bus.h>
#include <dev/accelerometer.h>
static mutex_t sensorbus_mutex;
static SPI_HandleTypeDef spi_handle;
static uint8_t tx_buff[16];
@@ -49,19 +49,7 @@ status_t acc_read_xyz(position_vector_t *pos_vector_p)
status_t acc_flush(uint8_t *tbuff, uint8_t *rbuff, uint8_t numbytes)
{
status_t ret_status;
mutex_acquire(&sensorbus_mutex);
gpio_set(GPIO_ACC_nCS,GPIO_PIN_RESET);
ret_status = HAL_SPI_TransmitReceive(&spi_handle, tbuff, rbuff, numbytes, 5000);
gpio_set(GPIO_ACC_nCS,GPIO_PIN_SET);
mutex_release(&sensorbus_mutex);
return ret_status;
return spi_transaction(&spi_handle, tbuff, rbuff, numbytes, GPIO_ACC_nCS);
}
/**
@@ -71,11 +59,6 @@ status_t acc_flush(uint8_t *tbuff, uint8_t *rbuff, uint8_t numbytes)
status_t sensor_bus_init_early(void)
{
__HAL_SENSOR_BUS_GPIO_CLK_ENABLE();
__HAL_RCC_SPI5_CLK_ENABLE();
gpio_config(GPIO_SPI5_SCK, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
gpio_config(GPIO_SPI5_MISO, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
gpio_config(GPIO_SPI5_MOSI, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
gpio_config(GPIO_NRF_CS, GPIO_OUTPUT );
gpio_config(GPIO_NRF_INT, GPIO_INPUT | GPIO_PULLUP);
@@ -109,11 +92,8 @@ status_t sensor_bus_init_early(void)
return NO_ERROR;
}
void sensor_bus_init(void)
{
mutex_init(&sensorbus_mutex);
}

View File

@@ -25,6 +25,7 @@ GLOBAL_DEFINES += \
MODULE_SRCS += \
$(LOCAL_DIR)/init.c \
$(LOCAL_DIR)/lcd.c \
$(LOCAL_DIR)/spi.c \
$(LOCAL_DIR)/usb.c
MODULE_DEPS += \