diff --git a/flight/AHRS/Makefile b/flight/AHRS/Makefile index 545794ff6..8d1e06ac2 100644 --- a/flight/AHRS/Makefile +++ b/flight/AHRS/Makefile @@ -86,6 +86,7 @@ CMSISDIR = $(STMLIBDIR)/CMSIS/Core/CM3 ## AHRS: SRC = ahrs.c +SRC += pios_board.c ## PIOS Hardware (STM32F10x) SRC += $(PIOSSTM32F10X)/pios_sys.c @@ -96,7 +97,7 @@ SRC += $(PIOSSTM32F10X)/pios_irq.c SRC += $(PIOSSTM32F10X)/pios_adc.c SRC += $(PIOSSTM32F10X)/pios_i2c.c SRC += $(PIOSSTM32F10X)/pios_gpio.c -#SRC += $(PIOSSTM32F10X)/pios_spi.c +SRC += $(PIOSSTM32F10X)/pios_spi.c ## PIOS Hardware (Common) SRC += $(PIOSCOMMON)/pios_com.c diff --git a/flight/AHRS/ahrs.c b/flight/AHRS/ahrs.c index 6962f77d8..270fd0e2d 100644 --- a/flight/AHRS/ahrs.c +++ b/flight/AHRS/ahrs.c @@ -71,6 +71,9 @@ int main() int16_t data[3] = {0}; int32_t heading = 0; + /* SPI link to master */ + PIOS_SPI_Init(); + // Main loop for(;;) { // Alive signal diff --git a/flight/AHRS/inc/pios_board.h b/flight/AHRS/inc/pios_board.h index f09107f3a..59a707e61 100644 --- a/flight/AHRS/inc/pios_board.h +++ b/flight/AHRS/inc/pios_board.h @@ -1,4 +1,4 @@ -/** + /** ****************************************************************************** * * @file pios_board.h @@ -115,6 +115,13 @@ TIM8 | | | | #define PIOS_I2C_IRQ_EV_PRIORITY 2 #define PIOS_I2C_IRQ_ER_PRIORITY 2 +//------------------------- +// SPI +// +// See also pios_board.c +//------------------------- +#define PIOS_OP_SPI 0 + //------------------------- // PIOS_USART1 //------------------------- diff --git a/flight/AHRS/inc/pios_config.h b/flight/AHRS/inc/pios_config.h index 4f3f118a6..752626690 100644 --- a/flight/AHRS/inc/pios_config.h +++ b/flight/AHRS/inc/pios_config.h @@ -34,6 +34,7 @@ #define PIOS_INCLUDE_I2C #define PIOS_INCLUDE_IRQ #define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_SPI #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_USART #define PIOS_INCLUDE_COM diff --git a/flight/AHRS/pios_board.c b/flight/AHRS/pios_board.c new file mode 100644 index 000000000..c7a952a6a --- /dev/null +++ b/flight/AHRS/pios_board.c @@ -0,0 +1,144 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the AHRS board. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#if defined(PIOS_INCLUDE_SPI) + +#include + +/* OP Interface + * + * NOTE: Leave this declared as const static data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_op_irq_handler(void); +static const struct pios_spi_cfg pios_spi_op_cfg = { + .regs = SPI2, + .init = { + .SPI_Mode = SPI_Mode_Slave, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Hard, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + }, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .handler = PIOS_SPI_op_irq_handler, + .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), + .init = { + .NVIC_IRQChannel = DMA1_Channel4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel4, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel5, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .ssel = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_12, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IN_FLOATING, + }, + }, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IN_FLOATING, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, +}; + +/* + * Board specific number of devices. + */ +struct pios_spi_dev pios_spi_devs[] = { + { + .cfg = &pios_spi_op_cfg, + }, +}; + +uint8_t pios_spi_num_devices = NELEMENTS(pios_spi_devs); + +void PIOS_SPI_op_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(PIOS_OP_SPI); +} + +#endif diff --git a/flight/OpenPilot/Makefile b/flight/OpenPilot/Makefile index da92947dd..1292a74e1 100644 --- a/flight/OpenPilot/Makefile +++ b/flight/OpenPilot/Makefile @@ -112,6 +112,7 @@ SRC += ${OUTDIR}/InitMods.c ## OPENPILOT CORE: SRC += ${OPMODULEDIR}/System/systemmod.c SRC += $(OPSYSTEM)/openpilot.c +SRC += $(OPSYSTEM)/pios_board.c SRC += $(OPSYSTEM)/alarms.c SRC += $(OPUAVTALK)/uavtalk.c SRC += $(OPUAVOBJ)/uavobjectmanager.c diff --git a/flight/OpenPilot/System/inc/pios_board.h b/flight/OpenPilot/System/inc/pios_board.h index 213b2a788..13e0640d7 100644 --- a/flight/OpenPilot/System/inc/pios_board.h +++ b/flight/OpenPilot/System/inc/pios_board.h @@ -162,44 +162,11 @@ TIM8 | Servo 5 | Servo 6 | Servo 7 | Servo 8 //------------------------- // SPI -//------------------------- -#define PIOS_SPI_IRQ_DMA_PRIORITY PIOS_IRQ_PRIO_HIGH -#define PIOS_SPI_NUM 2 -#define PIOS_SPI0_ENABLED 1 -#define PIOS_SPI0_PTR SPI1 -#define PIOS_SPI0_DMA_RX_PTR DMA1_Channel2 -#define PIOS_SPI0_DMA_TX_PTR DMA1_Channel3 -#define PIOS_SPI0_DMA_RX_IRQ_FLAGS (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2) -#define PIOS_SPI0_DMA_IRQ_CHANNEL DMA1_Channel2_IRQn -#define PIOS_SPI0_DMA_IRQHANDLER_FUNC void DMA1_Channel2_IRQHandler(void) -#define PIOS_SPI0_RCLK1_PORT GPIOA -#define PIOS_SPI0_RCLK1_PIN GPIO_Pin_4 -#define PIOS_SPI0_SCLK_PORT GPIOA -#define PIOS_SPI0_SCLK_PIN GPIO_Pin_5 -#define PIOS_SPI0_MISO_PORT GPIOA -#define PIOS_SPI0_MISO_PIN GPIO_Pin_6 -#define PIOS_SPI0_MOSI_PORT GPIOA -#define PIOS_SPI0_MOSI_PIN GPIO_Pin_7 -#define PIOS_SPI1_ENABLED 1 -#define PIOS_SPI1_PTR SPI2 -#define PIOS_SPI1_DMA_RX_PTR DMA1_Channel4 -#define PIOS_SPI1_DMA_TX_PTR DMA1_Channel5 -#define PIOS_SPI1_DMA_RX_IRQ_FLAGS (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4) -#define PIOS_SPI1_DMA_IRQ_CHANNEL DMA1_Channel4_IRQn -#define PIOS_SPI1_DMA_IRQHANDLER_FUNC void DMA1_Channel4_IRQHandler(void) -#define PIOS_SPI1_RCLK1_PORT GPIOB -#define PIOS_SPI1_RCLK1_PIN GPIO_Pin_12 -#define PIOS_SPI1_SCLK_PORT GPIOB -#define PIOS_SPI1_SCLK_PIN GPIO_Pin_13 -#define PIOS_SPI1_MISO_PORT GPIOB -#define PIOS_SPI1_MISO_PIN GPIO_Pin_14 -#define PIOS_SPI1_MOSI_PORT GPIOB -#define PIOS_SPI1_MOSI_PIN GPIO_Pin_15 - -//------------------------- -// PIOS_SDCARD +// +// See also pios_board.c //------------------------- #define PIOS_SDCARD_SPI 0 +#define PIOS_OPAHRS_SPI 1 //------------------------- // Delay Timer diff --git a/flight/OpenPilot/System/pios_board.c b/flight/OpenPilot/System/pios_board.c new file mode 100644 index 000000000..ab8b1265f --- /dev/null +++ b/flight/OpenPilot/System/pios_board.c @@ -0,0 +1,245 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the OpenPilot board. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +/* MicroSD Interface + * + * NOTE: Leave this declared as const static data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_sdcard_irq_handler(void); +const struct pios_spi_cfg pios_spi_sdcard_cfg = { + .regs = SPI1, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = 7 << 3, /* Maximum divider (ie. slowest clock rate) */ + }, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .handler = PIOS_SPI_sdcard_irq_handler, + .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), + .init = { + .NVIC_IRQChannel = DMA1_Channel2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel2, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel3, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .ssel = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_Out_PP, + }, + }, + .sclk = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, + .miso = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .mosi = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, +}; + +/* AHRS Interface + * + * NOTE: Leave this declared as const static data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_ahrs_irq_handler(void); +const struct pios_spi_cfg pios_spi_ahrs_cfg = { + .regs = SPI2, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = 7 << 3, /* Maximum divider (ie. slowest clock rate) */ + }, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .handler = PIOS_SPI_ahrs_irq_handler, + .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), + .init = { + .NVIC_IRQChannel = DMA1_Channel4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel4, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel5, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .ssel = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_12, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_Out_PP, + }, + }, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, +}; + +/* + * Board specific number of devices. + */ +struct pios_spi_dev pios_spi_devs[] = { + { + .cfg = &pios_spi_sdcard_cfg, + }, + { + .cfg = &pios_spi_ahrs_cfg, + }, +}; + +uint8_t pios_spi_num_devices = NELEMENTS(pios_spi_devs); + +void PIOS_SPI_sdcard_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(PIOS_SDCARD_SPI); +} + +void PIOS_SPI_ahrs_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(PIOS_OPAHRS_SPI); +} diff --git a/flight/PiOS/Common/pios_sdcard.c b/flight/PiOS/Common/pios_sdcard.c index b865893d5..df6347cbf 100644 --- a/flight/PiOS/Common/pios_sdcard.c +++ b/flight/PiOS/Common/pios_sdcard.c @@ -100,12 +100,12 @@ int32_t PIOS_SDCARD_Init(void) sdcard_mounted = 0; - /* Ensure that fast pin drivers are activated */ - PIOS_SPI_IO_Init(PIOS_SDCARD_SPI, PIOS_SPI_PIN_DRIVER_STRONG); + //PIOS_SPI_Init(PIOS_SDCARD_SPI); /* Init SPI port for slow frequency access (ca. 0.3 MBit/s) */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_256); + PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xFF); SDCARD_MUTEX_GIVE; /* No error */ @@ -127,7 +127,7 @@ int32_t PIOS_SDCARD_PowerOn(void) PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Init SPI port for slow frequency access (ca. 0.3 MBit/s) */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_256); /* Send 80 clock cycles to start up */ for(i=0; i<10; ++i) { @@ -270,7 +270,7 @@ int32_t PIOS_SDCARD_CheckAvailable(uint8_t was_available) if(was_available) { /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_4); /* Activate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 0); /* spi, pin_value */ @@ -279,7 +279,7 @@ int32_t PIOS_SDCARD_CheckAvailable(uint8_t was_available) ret = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_STATUS, 0, SDCMD_SEND_STATUS_CRC); } else { /* Ensure that SPI interface is clocked at low speed */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_256); /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ @@ -430,7 +430,7 @@ int32_t PIOS_SDCARD_SectorRead(uint32_t sector, uint8_t *buffer) /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* this is required for the case that the SPI port is shared with other devices */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_4); if((status=PIOS_SDCARD_SendSDCCmd(SDCMD_READ_SINGLE_BLOCK, sector, SDCMD_READ_SINGLE_BLOCK_CRC))) { status = (status < 0) ? -256 : status; /* return timeout indicator or error flags */ @@ -503,7 +503,7 @@ int32_t PIOS_SDCARD_SectorWrite(uint32_t sector, uint8_t *buffer) /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_4); if((status=PIOS_SDCARD_SendSDCCmd(SDCMD_WRITE_SINGLE_BLOCK, sector, SDCMD_WRITE_SINGLE_BLOCK_CRC))) { status = (status < 0) ? -256 : status; /* Return timeout indicator or error flags */ @@ -571,7 +571,7 @@ int32_t PIOS_SDCARD_CIDRead(SDCARDCidTypeDef *cid) /* This is required for the case that the SPI port is shared with other devices */ SDCARD_MUTEX_TAKE; - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_4); if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_CID, 0, SDCMD_SEND_CID_CRC))) { status = (status < 0) ? -256 : status; /* return timeout indicator or error flags */ @@ -661,7 +661,7 @@ int32_t PIOS_SDCARD_CSDRead(SDCARDCsdTypeDef *csd) /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ - PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); + PIOS_SPI_SetClockSpeed(PIOS_SDCARD_SPI, PIOS_SPI_PRESCALER_4); if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_CSD, 0, SDCMD_SEND_CSD_CRC))) { status = (status < 0) ? -256 : status; /* Return timeout indicator or error flags */ @@ -811,7 +811,7 @@ int32_t PIOS_SDCARD_StartupLog(void) /** * Check if the SD card has been mounted * @return 0 if no - * @return 1 if yes + * @return 1 if yes */ int32_t POIS_SDCARD_IsMounted() { diff --git a/flight/PiOS/STM32F10x/pios_spi.c b/flight/PiOS/STM32F10x/pios_spi.c index 096ad1acf..11e0989b4 100644 --- a/flight/PiOS/STM32F10x/pios_spi.c +++ b/flight/PiOS/STM32F10x/pios_spi.c @@ -8,7 +8,7 @@ * @see The GNU Public License (GPL) Version 3 * @defgroup PIOS_SPI SPI Functions * @notes - * J19 provides two RCLK (alias Chip Select) lines.
+ * J19 provides two SSEL (alias Chip Select) lines.
* It's a software emulated SPI, therefore the selected spi_prescaler has no * effect! Bytes are transfered so fast as possible. The usage of * PIOS_SPI_PIN_DRIVER_STRONG is strongly recommended ;)
@@ -41,12 +41,18 @@ #if defined(PIOS_INCLUDE_SPI) +#include -/* Local variables */ -static void (*spi_callback[PIOS_SPI_NUM])(void); -static uint8_t tx_dummy_byte; -static uint8_t rx_dummy_byte; +static struct pios_spi_dev * find_spi_dev_by_id (uint8_t spi) +{ + if (spi >= pios_spi_num_devices) { + /* Undefined SPI port for this board (see pios_board.c) */ + return NULL; + } + /* Get a handle for the device configuration */ + return &(pios_spi_devs[spi]); +} /** * Initialises SPI pins @@ -55,251 +61,94 @@ static uint8_t rx_dummy_byte; */ int32_t PIOS_SPI_Init(void) { - DMA_InitTypeDef DMA_InitStructure; - DMA_StructInit(&DMA_InitStructure); - NVIC_InitTypeDef NVIC_InitStructure; + struct pios_spi_dev * spi_dev; + uint8_t i; -#if (PIOS_SPI0_ENABLED) - /* SPI0 */ - /* Disable callback function */ - spi_callback[0] = NULL; + for (i = 0; i < pios_spi_num_devices; i++) { + /* Get a handle for the device configuration */ + spi_dev = find_spi_dev_by_id(i); + PIOS_DEBUG_Assert(spi_dev); - /* Set RC pin(s) to 1 */ - PIOS_SPI_RC_PinSet(0, 1); // spi, rc_pin, pin_value + /* Disable callback function */ + spi_dev->callback = NULL; - /* IO configuration */ - PIOS_SPI_IO_Init(0, PIOS_SPI_PIN_DRIVER_WEAK_OD); + /* Set rx/tx dummy bytes to a known value */ + spi_dev->rx_dummy_byte = 0xFF; + spi_dev->tx_dummy_byte = 0xFF; - /* Enable SPI peripheral clock (APB2 == high speed) */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + switch (spi_dev->cfg->init.SPI_NSS) { + case SPI_NSS_Soft: + if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) { + /* We're a master in soft NSS mode, make sure we see NSS high at all times. */ + SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set); + /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */ + GPIO_SetBits(spi_dev->cfg->ssel.gpio, spi_dev->cfg->ssel.init.GPIO_Pin); + GPIO_Init(spi_dev->cfg->ssel.gpio, &(spi_dev->cfg->ssel.init)); + } else { + /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */ + SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset); + } + break; + case SPI_NSS_Hard: + GPIO_Init(spi_dev->cfg->ssel.gpio, &(spi_dev->cfg->ssel.init)); + break; + default: + PIOS_DEBUG_Assert(0); + } + + /* Initialize the GPIO pins */ + GPIO_Init(spi_dev->cfg->sclk.gpio, &(spi_dev->cfg->sclk.init)); + GPIO_Init(spi_dev->cfg->mosi.gpio, &(spi_dev->cfg->mosi.init)); + GPIO_Init(spi_dev->cfg->miso.gpio, &(spi_dev->cfg->miso.init)); - /* Enable DMA1 clock */ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); + /* Enable the associated peripheral clock */ + switch ((uint32_t)spi_dev->cfg->regs) { + case (uint32_t)SPI1: + /* Enable SPI peripheral clock (APB2 == high speed) */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + break; + case (uint32_t)SPI2: + /* Enable SPI peripheral clock (APB1 == slow speed) */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + break; + case (uint32_t)SPI3: + /* Enable SPI peripheral clock (APB1 == slow speed) */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + break; + } + + /* Enable DMA clock */ + RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE); + + /* Configure DMA for SPI Rx */ + DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE); + DMA_Init(spi_dev->cfg->dma.rx.channel, &(spi_dev->cfg->dma.rx.init)); + + /* Configure DMA for SPI Tx */ + DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE); + DMA_Init(spi_dev->cfg->dma.tx.channel, &(spi_dev->cfg->dma.tx.init)); - /* DMA Configuration for SPI Rx Event */ - DMA_Cmd(PIOS_SPI0_DMA_RX_PTR, DISABLE); - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&PIOS_SPI0_PTR->DR; - DMA_InitStructure.DMA_MemoryBaseAddr = 0; /* Will be configured later */ - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; - DMA_InitStructure.DMA_BufferSize = 0; /* Will be configured later */ - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(PIOS_SPI0_DMA_RX_PTR, &DMA_InitStructure); + /* Initialize the SPI block */ + SPI_Init(spi_dev->cfg->regs, &(spi_dev->cfg->init)); - /* DMA Configuration for SPI Tx Event */ - /* (partly re-using previous DMA setup) */ - DMA_Cmd(PIOS_SPI0_DMA_TX_PTR, DISABLE); - DMA_InitStructure.DMA_MemoryBaseAddr = 0; /* Will be configured later */ - DMA_InitStructure.DMA_BufferSize = 0; /* Will be configured later */ - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_Init(PIOS_SPI0_DMA_TX_PTR, &DMA_InitStructure); + /* Enable SPI */ + SPI_Cmd(spi_dev->cfg->regs, ENABLE); - /* Initial SPI peripheral configuration */ - PIOS_SPI_TransferModeInit(0, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_128); + /* Enable SPI interrupts to DMA */ + SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); - /* Enable SPI */ - SPI_Cmd(PIOS_SPI0_PTR, ENABLE); + /* Configure DMA interrupt */ + NVIC_Init(&(spi_dev->cfg->dma.irq.init)); + } - /* Enable SPI interrupts to DMA */ - SPI_I2S_DMACmd(PIOS_SPI0_PTR, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); - - /* Configure DMA interrupt */ - NVIC_InitStructure.NVIC_IRQChannel = PIOS_SPI0_DMA_IRQ_CHANNEL; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_SPI_IRQ_DMA_PRIORITY; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); -#endif - -#if (PIOS_SPI1_ENABLED) - /* SPI1 */ - /* Disable callback function */ - spi_callback[1] = NULL; - - /* Set RC pin(s) to 1 */ - PIOS_SPI_RC_PinSet(1, 1); /* spi, pin_value */ - - /* IO configuration */ - PIOS_SPI_IO_Init(1, PIOS_SPI_PIN_DRIVER_WEAK_OD); - - /* Enable SPI peripheral clock (APB1 == slow speed) */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); - - /* Enable DMA1 clock */ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); - - /* DMA Configuration for SPI Rx Event */ - DMA_Cmd(PIOS_SPI1_DMA_RX_PTR, DISABLE); - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&PIOS_SPI1_PTR->DR; - DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; - DMA_InitStructure.DMA_BufferSize = 0; // will be configured later - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(PIOS_SPI1_DMA_RX_PTR, &DMA_InitStructure); - - /* DMA Configuration for SPI Tx Event */ - /* (partly re-using previous DMA setup) */ - DMA_Cmd(PIOS_SPI1_DMA_TX_PTR, DISABLE); - DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later - DMA_InitStructure.DMA_BufferSize = 0; // will be configured later - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_Init(PIOS_SPI1_DMA_TX_PTR, &DMA_InitStructure); - - /* Initial SPI peripheral configuration */ - PIOS_SPI_TransferModeInit(1, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_128); - - /* Enable SPI */ - SPI_Cmd(PIOS_SPI1_PTR, ENABLE); - - /* Enable SPI interrupts to DMA */ - SPI_I2S_DMACmd(PIOS_SPI1_PTR, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); - - /* Configure DMA interrupt */ - NVIC_InitStructure.NVIC_IRQChannel = PIOS_SPI1_DMA_IRQ_CHANNEL; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_SPI_IRQ_DMA_PRIORITY; /* defined in PIOS_irq.h */ - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); -#endif - - /* No error */ return 0; } /** -* (Re-)initializes SPI IO Pins -* By default, all output pins are configured with weak open drain drivers for 2 MHz -* \param[in] spi SPI number (0, 1 or 2) -* \param[in] spi_pin_driver configures the driver strength: -*
    -*
  • PIOS_SPI_PIN_DRIVER_STRONG: Configures outputs for up to 50 MHz -*
  • PIOS_SPI_PIN_DRIVER_STRONG_OD: Configures outputs as open drain -* for up to 50 MHz (allows voltage shifting via pull-resistors) -*
  • PIOS_SPI_PIN_DRIVER_WEAK: Configures outputs for up to 2 MHz (better EMC) -*
  • PIOS_SPI_PIN_DRIVER_WEAK_OD: Configures outputs as open drain for -* up to 2 MHz (allows voltage shifting via pull-resistors) -*
-* \return 0 if no error -* \return -1 if disabled SPI port selected -* \return -2 if unsupported SPI port selected -* \return -3 if unsupported pin driver mode -*/ -int32_t PIOS_SPI_IO_Init(uint8_t spi, SPIPinDriverTypeDef spi_pin_driver) -{ - /* Init GPIO structure */ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_StructInit(&GPIO_InitStructure); - - /* Select pin driver and output mode */ - uint32_t af_mode; - uint32_t gp_mode; - - switch(spi_pin_driver) { - case PIOS_SPI_PIN_DRIVER_STRONG: - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - af_mode = GPIO_Mode_AF_PP; - gp_mode = GPIO_Mode_Out_PP; - break; - - case PIOS_SPI_PIN_DRIVER_STRONG_OD: - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - af_mode = GPIO_Mode_AF_OD; - gp_mode = GPIO_Mode_Out_OD; - break; - - case PIOS_SPI_PIN_DRIVER_WEAK: - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - af_mode = GPIO_Mode_AF_PP; - gp_mode = GPIO_Mode_Out_PP; - break; - - case PIOS_SPI_PIN_DRIVER_WEAK_OD: - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - af_mode = GPIO_Mode_AF_OD; - gp_mode = GPIO_Mode_Out_OD; - break; - - default: - /* Unsupported pin driver mode */ - return -3; - } - - switch(spi) { - case 0: - /* SCLK and DOUT are outputs assigned to alternate functions */ - GPIO_InitStructure.GPIO_Mode = af_mode; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI0_SCLK_PIN; - GPIO_Init(PIOS_SPI0_SCLK_PORT, &GPIO_InitStructure); - GPIO_InitStructure.GPIO_Pin = PIOS_SPI0_MOSI_PIN; - GPIO_Init(PIOS_SPI0_MOSI_PORT, &GPIO_InitStructure); - - /* RCLK outputs assigned to GPIO */ - GPIO_InitStructure.GPIO_Mode = gp_mode; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI0_RCLK1_PIN; - GPIO_Init(PIOS_SPI0_RCLK1_PORT, &GPIO_InitStructure); - - /* DIN is input with pull-up */ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI0_MISO_PIN; - GPIO_Init(PIOS_SPI0_MISO_PORT, &GPIO_InitStructure); - break; - - case 1: - /* SCLK and DOUT are outputs assigned to alternate functions */ - GPIO_InitStructure.GPIO_Mode = af_mode; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI1_SCLK_PIN; - GPIO_Init(PIOS_SPI1_SCLK_PORT, &GPIO_InitStructure); - GPIO_InitStructure.GPIO_Pin = PIOS_SPI1_MOSI_PIN; - GPIO_Init(PIOS_SPI1_MOSI_PORT, &GPIO_InitStructure); - - /* RCLK outputs assigned to GPIO */ - GPIO_InitStructure.GPIO_Mode = gp_mode; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI1_RCLK1_PIN; - GPIO_Init(PIOS_SPI1_RCLK1_PORT, &GPIO_InitStructure); - - /* DIN is input with pull-up */ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - GPIO_InitStructure.GPIO_Pin = PIOS_SPI1_MISO_PIN; - GPIO_Init(PIOS_SPI1_MISO_PORT, &GPIO_InitStructure); - break; - - default: - /* Unsupported SPI port */ - return -2; - } - - /* No error */ - return 0; -} - - -/** -* (Re-)initialises SPI peripheral transfer mode -* By default, all SPI peripherals are configured with -* PIOS_SPI_MODE_CLK1_PHASE1 and PIOS_SPI_PRESCALER_128 +* (Re-)initialises SPI peripheral clock rate * * \param[in] spi SPI number (0 or 1) -* \param[in] spi_mode configures clock and capture phase: -*
    -*
  • PIOS_SPI_MODE_CLK0_PHASE0: Idle level of clock is 0, data captured at rising edge -*
  • PIOS_SPI_MODE_CLK0_PHASE1: Idle level of clock is 0, data captured at falling edge -*
  • PIOS_SPI_MODE_CLK1_PHASE0: Idle level of clock is 1, data captured at falling edge -*
  • PIOS_SPI_MODE_CLK1_PHASE1: Idle level of clock is 1, data captured at rising edge -*
* \param[in] spi_prescaler configures the SPI speed: *
    *
  • PIOS_SPI_PRESCALER_2: sets clock rate 27.7~ nS @ 72 MHz (36 MBit/s) (only supported for spi==0, spi1 uses 4 instead) @@ -315,94 +164,38 @@ int32_t PIOS_SPI_IO_Init(uint8_t spi, SPIPinDriverTypeDef spi_pin_driver) * \return -1 if disabled SPI port selected * \return -2 if unsupported SPI port selected * \return -3 if invalid spi_prescaler selected -* \return -4 if invalid spi_mode selected */ -int32_t PIOS_SPI_TransferModeInit(uint8_t spi, SPIModeTypeDef spi_mode, SPIPrescalerTypeDef spi_prescaler) +int32_t PIOS_SPI_SetClockSpeed(uint8_t spi, SPIPrescalerTypeDef spi_prescaler) { - /* SPI configuration */ - SPI_InitTypeDef SPI_InitStructure; - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; - SPI_InitStructure.SPI_Mode = SPI_Mode_Master; - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; + struct pios_spi_dev * spi_dev; + SPI_InitTypeDef SPI_InitStructure; - switch(spi_mode) { - case PIOS_SPI_MODE_CLK0_PHASE0: - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; - break; - case PIOS_SPI_MODE_CLK0_PHASE1: - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; - break; - case PIOS_SPI_MODE_CLK1_PHASE0: - SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; - break; - case PIOS_SPI_MODE_CLK1_PHASE1: - SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; - break; - default: - /* Invalid SPI clock/phase mode */ - return -4; - } + /* Get a handle for the device configuration */ + spi_dev = find_spi_dev_by_id(spi); - if(spi_prescaler >= 8) { - /* Invalid prescaler selected */ - return -3; - } + if (!spi_dev) { + /* Undefined SPI port for this board (see pios_board.c) */ + return -2; + } - switch(spi) { - case 0: { - uint16_t prev_cr1 = PIOS_SPI0_PTR->CR1; - /* SPI1 perpipheral is located in APB2 domain and clocked at full speed */ - /* therefore we have to add +1 to the prescaler */ - SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler&7) << 3; - SPI_Init(PIOS_SPI0_PTR, &SPI_InitStructure); + if(spi_prescaler >= 8) { + /* Invalid prescaler selected */ + return -3; + } - if((prev_cr1 ^ PIOS_SPI0_PTR->CR1) & 3) { - /* CPOL and CPHA located at bit #1 and #0 */ - /* clock configuration has been changed - we should send a dummy byte */ - /* before the application activates chip select. */ - /* this solves a dependency between SDCard and ENC28J60 driver */ - PIOS_SPI_TransferByte(spi, 0xff); - } + /* Start with a copy of the default configuration for the peripheral */ + SPI_InitStructure = spi_dev->cfg->init; - } break; + /* Adjust the prescaler for the peripheral's clock */ + SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3; - case 1: { - uint16_t prev_cr1 = PIOS_SPI1_PTR->CR1; + /* Write back the new configuration */ + SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure); - /* SPI2 perpipheral is located in APB1 domain and clocked at half speed */ - if(spi_prescaler == 0) { - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; - } else { - SPI_InitStructure.SPI_BaudRatePrescaler = (((uint16_t)spi_prescaler&7)-1) << 3; - } - SPI_Init(PIOS_SPI1_PTR, &SPI_InitStructure); - - if((prev_cr1 ^ PIOS_SPI1_PTR->CR1) & 3) { - /* CPOL and CPHA located at bit #1 and #0 */ - /* clock configuration has been changed - we should send a dummy byte */ - /* before the application activates chip select. */ - /* this solves a dependency between SDCard and ENC28J60 driver */ - PIOS_SPI_TransferByte(spi, 0xff); - } - } break; - - default: - /* Unsupported SPI port */ - return -2; - } - - /* No error */ - return 0; + PIOS_SPI_TransferByte(spi, 0xFF); + return 0; } - /** * Controls the RC (Register Clock alias Chip Select) pin of a SPI port * \param[in] spi SPI number (0 or 1) @@ -413,34 +206,25 @@ int32_t PIOS_SPI_TransferModeInit(uint8_t spi, SPIModeTypeDef spi_mode, SPIPresc */ int32_t PIOS_SPI_RC_PinSet(uint8_t spi, uint8_t pin_value) { - switch(spi) { - case 0: - if(pin_value) { - PIOS_SPI0_RCLK1_PORT->BSRR = PIOS_SPI0_RCLK1_PIN; - } else { - PIOS_SPI0_RCLK1_PORT->BRR = PIOS_SPI0_RCLK1_PIN; - } - break; + struct pios_spi_dev * spi_dev; - case 1: - if(pin_value) { - PIOS_SPI1_RCLK1_PORT->BSRR = PIOS_SPI1_RCLK1_PIN; - } else { - PIOS_SPI1_RCLK1_PORT->BRR = PIOS_SPI1_RCLK1_PIN; - } + /* Get a handle for the device configuration */ + spi_dev = find_spi_dev_by_id(spi); - break; + if (!spi_dev) { + /* Undefined SPI port for this board (see pios_board.c) */ + return -2; + } - default: - /* Unsupported SPI port */ - return -2; - } + if (pin_value) { + GPIO_SetBits(spi_dev->cfg->ssel.gpio, spi_dev->cfg->ssel.init.GPIO_Pin); + } else { + GPIO_ResetBits(spi_dev->cfg->ssel.gpio, spi_dev->cfg->ssel.init.GPIO_Pin); + } - /* No error */ - return 0; + return 0; } - /** * Transfers a byte to SPI output and reads back the return value from SPI input * \param[in] spi SPI number (0 or 1) @@ -452,41 +236,42 @@ int32_t PIOS_SPI_RC_PinSet(uint8_t spi, uint8_t pin_value) */ int32_t PIOS_SPI_TransferByte(uint8_t spi, uint8_t b) { - SPI_TypeDef *spi_ptr; + struct pios_spi_dev * spi_dev; + uint8_t dummy; + uint8_t rx_byte; - switch(spi) { - case 0: - spi_ptr = PIOS_SPI0_PTR; - break; + /* Get a handle for the device configuration */ + spi_dev = find_spi_dev_by_id(spi); - case 1: - spi_ptr = PIOS_SPI1_PTR; - break; + if (!spi_dev) { + /* Undefined SPI port for this board (see pios_board.c) */ + return -2; + } - default: - /* Unsupported SPI port */ - return -2; - } + /* + * Procedure taken from STM32F10xxx Reference Manual section 23.3.5 + */ - /* Send byte */ - spi_ptr->DR = b; + /* Make sure the RXNE flag is cleared by reading the DR register */ + dummy = spi_dev->cfg->regs->DR; - if(spi_ptr->SR); /* Dummy read due to undocumented pipelining issue :-/ */ - /* TK: without this read (which can be done to any bus location) we could sporadically */ - /* get the status byte at the moment where DR is written. Accordingly, the busy bit */ - /* will be 0. */ - /* you won't see this dummy read in STM drivers, as they never have a DR write */ - /* followed by SR read, or as they are using SPI1/SPI2 pointers, which results into */ - /* some additional CPU instructions between strh/ldrh accesses. */ - /* We use a bus access instead of NOPs to avoid any risk for back-to-back transactions */ - /* over AHB (if SPI1/SPI2 pointers are used, there is still a risk for such a scenario, */ - /* e.g. if DMA loads the bus!) */ + /* Start the transfer */ + spi_dev->cfg->regs->DR = b; - /* Wait until SPI transfer finished */ - while(spi_ptr->SR & SPI_I2S_FLAG_BSY); + /* Wait until there is a byte to read */ + while(!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_RXNE)); - /* Return received byte */ - return spi_ptr->DR; + /* Read the rx'd byte */ + rx_byte = spi_dev->cfg->regs->DR; + + /* Wait until the TXE goes high */ + while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)); + + /* Wait for SPI transfer to have fully completed */ + while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY); + + /* Return received byte */ + return rx_byte; } @@ -509,94 +294,90 @@ int32_t PIOS_SPI_TransferByte(uint8_t spi, uint8_t b) */ int32_t PIOS_SPI_TransferBlock(uint8_t spi, uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback) { - DMA_Channel_TypeDef *dma_tx_ptr, *dma_rx_ptr; + struct pios_spi_dev * spi_dev; + DMA_InitTypeDef dma_init; - switch(spi) { - case 0: - dma_tx_ptr = PIOS_SPI0_DMA_TX_PTR; - dma_rx_ptr = PIOS_SPI0_DMA_RX_PTR; - break; + /* Get a handle for the device configuration */ + spi_dev = find_spi_dev_by_id(spi); - case 1: - dma_tx_ptr = PIOS_SPI1_DMA_TX_PTR; - dma_rx_ptr = PIOS_SPI1_DMA_RX_PTR; - break; + if (!spi_dev) { + /* Undefined SPI port for this board (see pios_board.c) */ + return -2; + } - default: - /* Unsupported SPI port */ - return -2; - } - /* Exit if ongoing transfer */ - if(dma_rx_ptr->CNDTR) { - return -3; - } + /* Exit if ongoing transfer */ + if(spi_dev->cfg->dma.rx.channel->CNDTR) { + return -3; + } - /* Set callback function */ - spi_callback[spi] = callback; + /* Set callback function */ + spi_dev->callback = callback; - /* Configure Rx channel */ - DMA_Cmd(dma_rx_ptr, DISABLE); - if(receive_buffer != NULL) { - /* Enable memory addr. increment - bytes written into receive buffer */ - dma_rx_ptr->CMAR = (uint32_t)receive_buffer; - dma_rx_ptr->CCR |= DMA_MemoryInc_Enable; - } else { - /* Disable memory addr. increment - bytes written into dummy buffer */ - rx_dummy_byte = 0xff; - dma_rx_ptr->CMAR = (uint32_t)&rx_dummy_byte; - dma_rx_ptr->CCR &= ~DMA_MemoryInc_Enable; - } - dma_rx_ptr->CNDTR = len; - DMA_Cmd(dma_rx_ptr, ENABLE); + /* Configure Rx channel */ + DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE); - /* Configure Tx channel */ - DMA_Cmd(dma_tx_ptr, DISABLE); - if(send_buffer != NULL) { - /* Enable memory addr. increment - bytes read from send buffer */ - dma_tx_ptr->CMAR = (uint32_t)send_buffer; - dma_tx_ptr->CCR |= DMA_MemoryInc_Enable; - } else { - /* Disable memory addr. increment - bytes read from dummy buffer */ - tx_dummy_byte = 0xff; - dma_tx_ptr->CMAR = (uint32_t)&tx_dummy_byte; - dma_tx_ptr->CCR &= ~DMA_MemoryInc_Enable; - } - dma_tx_ptr->CNDTR = len; + /* Start with the default configuration for this peripheral */ + dma_init = spi_dev->cfg->dma.rx.init; - /* Enable DMA interrupt if callback function active */ - DMA_ITConfig(dma_rx_ptr, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE); + if(receive_buffer != NULL) { + /* Enable memory addr. increment - bytes written into receive buffer */ + dma_init.DMA_MemoryBaseAddr = (uint32_t)receive_buffer; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; + } else { + /* Disable memory addr. increment - bytes written into dummy buffer */ + spi_dev->rx_dummy_byte = 0xff; + dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->rx_dummy_byte; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + dma_init.DMA_MemoryDataSize = len; + DMA_Init(spi_dev->cfg->dma.rx.channel, &(dma_init)); + DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE); - /* Start DMA transfer */ - DMA_Cmd(dma_tx_ptr, ENABLE); + /* Configure Tx channel */ + DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE); - /* Wait until all bytes have been transmitted/received */ - while(dma_rx_ptr->CNDTR); + /* Start with the default configuration for this peripheral */ + dma_init = spi_dev->cfg->dma.tx.init; - /* No error */ - return 0; + if(send_buffer != NULL) { + /* Enable memory addr. increment - bytes written into receive buffer */ + dma_init.DMA_MemoryBaseAddr = (uint32_t)send_buffer; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; + } else { + /* Disable memory addr. increment - bytes written into dummy buffer */ + spi_dev->tx_dummy_byte = 0xff; + dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->tx_dummy_byte; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + dma_init.DMA_MemoryDataSize = len; + DMA_Init(spi_dev->cfg->dma.tx.channel, &(dma_init)); + + /* Enable DMA interrupt if callback function active */ + DMA_ITConfig(spi_dev->cfg->dma.rx.channel, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE); + + /* Start DMA Tx transfer */ + DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE); + + /* Wait until all bytes have been transmitted/received */ + while(DMA_GetCurrDataCounter(spi_dev->cfg->dma.tx.channel)); + + /* No error */ + return 0; } - -/** -* Called when callback function has been defined and SPI transfer has finished -*/ -PIOS_SPI0_DMA_IRQHANDLER_FUNC +void PIOS_SPI_IRQ_Handler(uint8_t spi) { - DMA_ClearFlag(PIOS_SPI0_DMA_RX_IRQ_FLAGS); + struct pios_spi_dev * spi_dev; - if(spi_callback[0] != NULL) { - spi_callback[0](); - } -} + spi_dev = find_spi_dev_by_id (spi); + PIOS_DEBUG_Assert(spi_dev); -PIOS_SPI1_DMA_IRQHANDLER_FUNC -{ - DMA_ClearFlag(PIOS_SPI1_DMA_RX_IRQ_FLAGS); + DMA_ClearFlag(spi_dev->cfg->dma.irq.flags); - if(spi_callback[1] != NULL) { - spi_callback[1](); - } + if(spi_dev->callback != NULL) { + spi_dev->callback(); + } } #endif diff --git a/flight/PiOS/inc/pios_spi.h b/flight/PiOS/inc/pios_spi.h index 723e93db1..7d3da8bf3 100644 --- a/flight/PiOS/inc/pios_spi.h +++ b/flight/PiOS/inc/pios_spi.h @@ -28,20 +28,6 @@ #define PIOS_SPI_H /* Global types */ -typedef enum { - PIOS_SPI_PIN_DRIVER_STRONG = 0, - PIOS_SPI_PIN_DRIVER_STRONG_OD = 1, - PIOS_SPI_PIN_DRIVER_WEAK = 2, - PIOS_SPI_PIN_DRIVER_WEAK_OD = 3, -} SPIPinDriverTypeDef; - -typedef enum { - PIOS_SPI_MODE_CLK0_PHASE0 = 0, - PIOS_SPI_MODE_CLK0_PHASE1 = 1, - PIOS_SPI_MODE_CLK1_PHASE0 = 2, - PIOS_SPI_MODE_CLK1_PHASE1 = 3 -} SPIModeTypeDef; - typedef enum { PIOS_SPI_PRESCALER_2 = 0, PIOS_SPI_PRESCALER_4 = 1, @@ -53,13 +39,12 @@ typedef enum { PIOS_SPI_PRESCALER_256 = 7 } SPIPrescalerTypeDef; - -/* PUblic Functions */ +/* Public Functions */ extern int32_t PIOS_SPI_Init(void); -extern int32_t PIOS_SPI_IO_Init(uint8_t spi, SPIPinDriverTypeDef spi_pin_driver); -extern int32_t PIOS_SPI_TransferModeInit(uint8_t spi, SPIModeTypeDef spi_mode, SPIPrescalerTypeDef spi_prescaler); +extern int32_t PIOS_SPI_SetClockSpeed(uint8_t spi, SPIPrescalerTypeDef spi_prescaler); extern int32_t PIOS_SPI_RC_PinSet(uint8_t spi, uint8_t pin_value); extern int32_t PIOS_SPI_TransferByte(uint8_t spi, uint8_t b); extern int32_t PIOS_SPI_TransferBlock(uint8_t spi, uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback); +extern void PIOS_SPI_IRQ_Handler(uint8_t spi); -#endif /* PIOS_SSPI_H */ +#endif /* PIOS_SPI_H */ diff --git a/flight/PiOS/inc/pios_spi_priv.h b/flight/PiOS/inc/pios_spi_priv.h new file mode 100644 index 000000000..9a480738e --- /dev/null +++ b/flight/PiOS/inc/pios_spi_priv.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * + * @file pios_spi_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief SPI private definitions. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_SPI_PRIV_H +#define PIOS_SPI_PRIV_H + +#include +#include + +struct pios_spi_cfg { + SPI_TypeDef * regs; + SPI_InitTypeDef init; + bool * master; + struct stm32_dma dma; + struct stm32_gpio ssel; + struct stm32_gpio sclk; + struct stm32_gpio miso; + struct stm32_gpio mosi; +}; + +struct pios_spi_dev { + const struct pios_spi_cfg * const cfg; + void (*callback)(void); + uint8_t tx_dummy_byte; + uint8_t rx_dummy_byte; +}; + +extern struct pios_spi_dev pios_spi_devs[]; +extern uint8_t pios_spi_num_devices; + +#endif /* PIOS_SPI_PRIV_H */ diff --git a/flight/PiOS/inc/pios_stm32.h b/flight/PiOS/inc/pios_stm32.h new file mode 100644 index 000000000..5034ae43a --- /dev/null +++ b/flight/PiOS/inc/pios_stm32.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file pios_stm32.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Types that are specific to the STM32 peripherals + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_STM32_H +#define PIOS_STM32_H + +struct stm32_irq { + void (*handler)(void); + uint32_t flags; + NVIC_InitTypeDef init; +}; + +struct stm32_dma_chan { + DMA_Channel_TypeDef * channel; + DMA_InitTypeDef init; +}; + +struct stm32_dma { + uint32_t ahb_clk; + struct stm32_irq irq; + struct stm32_dma_chan rx; + struct stm32_dma_chan tx; +}; + +struct stm32_gpio { + GPIO_TypeDef * gpio; + GPIO_InitTypeDef init; +}; + +#endif /* PIOS_STM32_H */ diff --git a/flight/PiOS/pios.h b/flight/PiOS/pios.h index 5f1994699..bfa83649c 100644 --- a/flight/PiOS/pios.h +++ b/flight/PiOS/pios.h @@ -28,9 +28,8 @@ #ifndef PIOS_H #define PIOS_H -/* PIOS Compile Time Configuration */ +/* PIOS Feature Selection */ #include "pios_config.h" -#include "pios_board.h" #if defined(PIOS_INCLUDE_FREERTOS) /* FreeRTOS Includes */ @@ -62,6 +61,9 @@ #include #endif +/* PIOS Board Specific Device Configuration */ +#include "pios_board.h" + /* PIOS Hardware Includes (STM32F10x) */ #include #include @@ -100,4 +102,6 @@ #include #endif +#define NELEMENTS(x) (sizeof(x) / sizeof(*(x))) + #endif /* PIOS_H */