Files
Maison/OpenSky/arch/stm32f1/hal_spi.c
2026-04-21 12:19:15 +02:00

195 lines
6.6 KiB
C

/*
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);
}