Ajout FishPeper
This commit is contained in:
194
OpenSky/arch/stm32f1/hal_spi.c
Normal file
194
OpenSky/arch/stm32f1/hal_spi.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright 2017 fishpepper <AT> gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http:// www.gnu.org/licenses/>.
|
||||
|
||||
author: fishpepper <AT> gmail.com
|
||||
*/
|
||||
|
||||
#include "hal_spi.h"
|
||||
#include "debug.h"
|
||||
#include "led.h"
|
||||
#include "config.h"
|
||||
#include "stm32f10x_gpio.h"
|
||||
#include "stm32f10x_spi.h"
|
||||
#include "stm32f10x_rcc.h"
|
||||
#include "stm32f10x_dma.h"
|
||||
|
||||
|
||||
void hal_spi_init(void) {
|
||||
hal_spi_init_rcc();
|
||||
hal_spi_init_gpio();
|
||||
hal_spi_init_mode();
|
||||
hal_spi_init_dma();
|
||||
hal_spi_enable();
|
||||
}
|
||||
|
||||
static void hal_spi_init_rcc(void) {
|
||||
// enable clocks
|
||||
RCC_APB2PeriphClockCmd(CC25XX_SPI_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);
|
||||
RCC_APBxPeriphClockCmd(CC25XX_SPI_CLK_RCC, CC25XX_SPI_CLK, ENABLE);
|
||||
}
|
||||
|
||||
static void hal_spi_enable(void) {
|
||||
SPI_Cmd(CC25XX_SPI, ENABLE);
|
||||
}
|
||||
|
||||
static void hal_spi_init_mode(void) {
|
||||
SPI_InitTypeDef spi_init;
|
||||
|
||||
// mode config
|
||||
spi_init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
||||
spi_init.SPI_Mode = SPI_Mode_Master;
|
||||
spi_init.SPI_DataSize = SPI_DataSize_8b;
|
||||
spi_init.SPI_CPOL = SPI_CPOL_Low;
|
||||
spi_init.SPI_CPHA = SPI_CPHA_1Edge;
|
||||
spi_init.SPI_NSS = SPI_NSS_Soft;
|
||||
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // = 3 MHz
|
||||
spi_init.SPI_FirstBit = SPI_FirstBit_MSB;
|
||||
spi_init.SPI_CRCPolynomial = 7;
|
||||
SPI_Init(CC25XX_SPI, &spi_init);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void hal_spi_init_dma(void) {
|
||||
DMA_InitTypeDef dma_init;
|
||||
|
||||
// Enable DMA1 Peripheral Clock
|
||||
RCC_AHBPeriphClockCmd(CC25XX_SPI_DMA_CLOCK, ENABLE);
|
||||
|
||||
// Configure SPI RX Channel
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
dma_init.DMA_PeripheralBaseAddr = (uint32_t)&CC25XX_SPI->DR;
|
||||
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
dma_init.DMA_MemoryBaseAddr = 0; // will be set later
|
||||
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
dma_init.DMA_BufferSize = 1; // will be set later
|
||||
dma_init.DMA_Mode = DMA_Mode_Normal;
|
||||
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(CC25XX_SPI_RX_DMA_CHANNEL, &dma_init);
|
||||
|
||||
// configure SPI TX Channel
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||
dma_init.DMA_PeripheralBaseAddr = (uint32_t)&CC25XX_SPI->DR;
|
||||
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
dma_init.DMA_MemoryBaseAddr = 0; // will be set later
|
||||
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
dma_init.DMA_BufferSize = 1; // will be set later
|
||||
dma_init.DMA_Mode = DMA_Mode_Normal;
|
||||
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(CC25XX_SPI_TX_DMA_CHANNEL, &dma_init);
|
||||
|
||||
// start disabled
|
||||
DMA_Cmd(CC25XX_SPI_TX_DMA_CHANNEL, DISABLE);
|
||||
DMA_Cmd(CC25XX_SPI_RX_DMA_CHANNEL, DISABLE);
|
||||
}
|
||||
|
||||
// data in buffer will be sent and will be overwritten with
|
||||
// the data read back from the spi slave
|
||||
void hal_spi_dma_xfer(uint8_t *buffer, uint8_t len) {
|
||||
// debug("xfer "); debug_put_uint8(len); debug(")\n");
|
||||
|
||||
// TX: transfer buffer to slave
|
||||
CC25XX_SPI_TX_DMA_CHANNEL->CMAR = (uint32_t)buffer;
|
||||
CC25XX_SPI_TX_DMA_CHANNEL->CNDTR = len;
|
||||
|
||||
// RX: read back data from slave
|
||||
CC25XX_SPI_RX_DMA_CHANNEL->CMAR = (uint32_t)buffer;
|
||||
CC25XX_SPI_RX_DMA_CHANNEL->CNDTR = len;
|
||||
|
||||
// enable both dma
|
||||
DMA_Cmd(CC25XX_SPI_RX_DMA_CHANNEL, ENABLE);
|
||||
DMA_Cmd(CC25XX_SPI_TX_DMA_CHANNEL, ENABLE);
|
||||
|
||||
// debug("DMA EN\n"); debug_flush();
|
||||
|
||||
// trigger the SPI TX + RX dma
|
||||
SPI_I2S_DMACmd(CC25XX_SPI, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
|
||||
|
||||
// debug("TRIG\n"); debug_flush();
|
||||
#if 0
|
||||
// Wait until the command is sent to the DR
|
||||
while (!DMA_GetFlagStatus(CC25XX_SPI_TX_DMA_TC_FLAG)) {}
|
||||
|
||||
// debug("ACTIVE\n"); debug_flush();
|
||||
|
||||
// wait for tx to be finished:
|
||||
while (DMA_GetFlagStatus(CC25XX_SPI_TX_DMA_TC_FLAG)) {}
|
||||
while (DMA_GetFlagStatus(CC25XX_SPI_RX_DMA_TC_FLAG)) {}
|
||||
|
||||
// wait for SPI to be no longer busy
|
||||
while (SPI_I2S_GetFlagStatus(CC25XX_SPI, SPI_I2S_FLAG_BSY) != RESET) {}
|
||||
// debug("!BUSY\n"); debug_flush();
|
||||
#endif // 0
|
||||
|
||||
while (SPI_I2S_GetFlagStatus(CC25XX_SPI, SPI_I2S_FLAG_TXE) == RESET) {}
|
||||
while (SPI_I2S_GetFlagStatus(CC25XX_SPI, SPI_I2S_FLAG_BSY) != RESET) {}
|
||||
|
||||
// while ((SPI1->SR & 2) == 0); // wait while TXE flag is 0 (TX is not empty)
|
||||
// while ((SPI1->SR & (1 << 7)) != 0); // wait while BSY flag is 1 (SPI is busy)
|
||||
|
||||
// disable DMA
|
||||
DMA_Cmd(CC25XX_SPI_RX_DMA_CHANNEL, DISABLE);
|
||||
DMA_Cmd(CC25XX_SPI_TX_DMA_CHANNEL, DISABLE);
|
||||
|
||||
// clear DMA flags
|
||||
SPI_I2S_DMACmd(CC25XX_SPI, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, DISABLE);
|
||||
}
|
||||
|
||||
|
||||
static void hal_spi_init_gpio(void) {
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// configure SCK and MOSI pins as Alternate Function Push-Pull
|
||||
gpio_init.GPIO_Pin = CC25XX_SPI_SCK_PIN | CC25XX_SPI_MOSI_PIN;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_Init(CC25XX_SPI_GPIO, &gpio_init);
|
||||
|
||||
// configure CSN as Push-Pull
|
||||
gpio_init.GPIO_Pin = CC25XX_SPI_CSN_PIN;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(CC25XX_SPI_GPIO, &gpio_init);
|
||||
|
||||
// configure MISO pin as Input floating
|
||||
gpio_init.GPIO_Pin = CC25XX_SPI_MISO_PIN;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(CC25XX_SPI_GPIO, &gpio_init);
|
||||
}
|
||||
|
||||
uint8_t hal_spi_tx(uint8_t address) {
|
||||
// wait for SPI Tx buffer empty
|
||||
while (SPI_I2S_GetFlagStatus(CC25XX_SPI, SPI_I2S_FLAG_TXE) == RESET) {}
|
||||
// send SPI data
|
||||
SPI_I2S_SendData(CC25XX_SPI, address);
|
||||
|
||||
// read response
|
||||
while (SPI_I2S_GetFlagStatus(CC25XX_SPI, SPI_I2S_FLAG_RXNE) == RESET) {}
|
||||
uint8_t result = SPI_I2S_ReceiveData(CC25XX_SPI);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint8_t hal_spi_rx(void) {
|
||||
return hal_spi_tx(0xff);
|
||||
}
|
||||
Reference in New Issue
Block a user