196 lines
6.9 KiB
C
196 lines
6.9 KiB
C
/*
|
|
* spi.c
|
|
*
|
|
* Created on: 3 okt. 2016
|
|
* Author: len12007
|
|
*/
|
|
|
|
|
|
|
|
#include "drivers/spi.h"
|
|
#include "stm32f4xx_revo.h"
|
|
|
|
// handles to SPI1 and SPI3
|
|
SPI_HandleTypeDef spi_channels[2];
|
|
bool spi_handel_initialized[2] = { false };
|
|
|
|
|
|
/****************************************************************************
|
|
* BRIEF: initializes a slave on the selected SPI instance *
|
|
* INFORMATION: Initialize a slave on the SPI. The SPI bus will only be *
|
|
* initialized once only per bus and if several slaves are used on the *
|
|
* same bus this function will return the struct with the pre initialized *
|
|
* SPI bus and the correct pin and port. *
|
|
***************************************************************************/
|
|
bool spi_init(SPI_TypeDef *spi_instance, // The spi instance to be used i.e. SPI1 or SPI3 on the REVO
|
|
spi_profile *out_profile, // The output profile to be used when sending and receiving data
|
|
uint32_t nss_pin, // The Slave Select Pin
|
|
GPIO_TypeDef *nss_port) // The port of the Slave Select Pin
|
|
{
|
|
uint32_t spi_af, spi_miso, spi_mosi, spi_sck;
|
|
GPIO_TypeDef *spi_miso_port;
|
|
uint8_t spi_handle;
|
|
out_profile->spi_nss = nss_pin;
|
|
out_profile->spi_nss_port = nss_port;
|
|
|
|
// Get the pins, ports and alternate functions for the seleceted SPI
|
|
if(spi_instance == SPI1)
|
|
{
|
|
spi_handle = 0; // The index to SPI1 bus to initialize and attache to the out_profile struct
|
|
spi_miso = SPI1_MISO;
|
|
spi_mosi = SPI1_MOSI;
|
|
spi_sck = SPI1_SCK;
|
|
spi_miso_port = SPI1_MISO_PORT;
|
|
spi_af = GPIO_AF5_SPI1;
|
|
|
|
// Start the spi clock if not already started
|
|
if(__SPI1_IS_CLK_DISABLED())
|
|
__SPI1_CLK_ENABLE();
|
|
}
|
|
else if(spi_instance == SPI3)
|
|
{
|
|
spi_handle = 1;
|
|
spi_miso = SPI3_MISO;
|
|
spi_mosi = SPI3_MOSI;
|
|
spi_sck = SPI3_SCK;
|
|
spi_af = GPIO_AF6_SPI3;
|
|
spi_miso_port = SPI3_MISO_PORT;
|
|
|
|
if(__SPI3_IS_CLK_DISABLED())
|
|
__SPI3_CLK_ENABLE();
|
|
}
|
|
else
|
|
return false; // If the given SPI Instance is not available on the REVO board
|
|
|
|
out_profile->profile = &spi_channels[spi_handle];
|
|
|
|
// Set up the NSS pin
|
|
GPIO_InitTypeDef gpioInit;
|
|
gpioInit.Pin = out_profile->spi_nss;
|
|
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
|
|
gpioInit.Pull = GPIO_PULLUP;
|
|
gpioInit.Speed = GPIO_SPEED_HIGH;
|
|
gpioInit.Alternate = 0;
|
|
HAL_GPIO_Init(out_profile->spi_nss_port, &gpioInit);
|
|
|
|
// If the SPI bus is already initialized we can finish here
|
|
if(spi_handel_initialized[spi_handle])
|
|
return true;
|
|
|
|
// setup spi miso, mosi and clock pins
|
|
gpioInit.Pin = spi_miso | spi_mosi | spi_sck;
|
|
gpioInit.Mode = GPIO_MODE_AF_PP;
|
|
gpioInit.Pull = GPIO_NOPULL;
|
|
gpioInit.Speed = GPIO_SPEED_HIGH;
|
|
gpioInit.Alternate = spi_af;
|
|
HAL_GPIO_Init(spi_miso_port, &gpioInit);
|
|
|
|
// Set up all parameters for the SPI communication
|
|
out_profile->profile->Instance = spi_instance;
|
|
out_profile->profile->Init.Mode = SPI_MODE_MASTER;
|
|
out_profile->profile->Init.Direction = SPI_DIRECTION_2LINES;
|
|
out_profile->profile->Init.DataSize = SPI_DATASIZE_8BIT;
|
|
out_profile->profile->Init.CLKPolarity = SPI_POLARITY_LOW;
|
|
out_profile->profile->Init.CLKPhase = SPI_PHASE_1EDGE;
|
|
out_profile->profile->Init.NSS = SPI_NSS_HARD_OUTPUT;
|
|
out_profile->profile->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
|
|
out_profile->profile->Init.FirstBit = SPI_FIRSTBIT_MSB;
|
|
out_profile->profile->Init.TIMode = SPI_TIMODE_DISABLE;
|
|
out_profile->profile->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
|
|
|
|
// Initialize the spi
|
|
if(HAL_SPI_Init(out_profile->profile) != HAL_OK)
|
|
return false;
|
|
|
|
// Set the initialized variable to true, this make sure that the SPI bus is
|
|
// only set up once.
|
|
spi_handel_initialized[spi_handle] = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* BRIEF: transmit data to the selected slave over SPI *
|
|
* INFORMATION: *
|
|
* data[0] = register *
|
|
* data[1..n] = command *
|
|
***********************************************************************/
|
|
bool spi_transmit(spi_profile *profile,
|
|
uint8_t *data,
|
|
uint32_t length,
|
|
uint32_t timeout_ms)
|
|
{
|
|
HAL_StatusTypeDef err; /* SPI transmission status variable */
|
|
|
|
// Tell the selected slave that the data is intended for him/her (hen)
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_RESET);
|
|
// Send the data
|
|
err = HAL_SPI_Transmit(profile->profile, data, length, timeout_ms);
|
|
// Tell the selected slave that we are done for now
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_SET);
|
|
|
|
return (err == HAL_OK);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* BRIEF: request data from selected slave on specified register *
|
|
* INFORMATION: By passing in a register we can request specified *
|
|
* data over the SPI bus *
|
|
***********************************************************************/
|
|
bool spi_receive_reg_value(spi_profile *profile,
|
|
uint8_t reg,
|
|
uint8_t *data,
|
|
uint32_t length,
|
|
uint32_t timeout_ms)
|
|
{
|
|
HAL_StatusTypeDef err; /* SPI transmission status variable */
|
|
|
|
uint8_t tmpData[length+1]; /* Temporary data variable */
|
|
tmpData[0] = reg | 0x80; /* Flips the request for data bit */
|
|
|
|
// Tell the selected slave that the data is intended for him/her (hen)
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_RESET);
|
|
// Send request and receive the response
|
|
err = HAL_SPI_TransmitReceive(profile->profile, tmpData, tmpData, length + 1, timeout_ms);
|
|
// Tell the selected slave that we are done for now
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_SET);
|
|
if(err != HAL_OK)
|
|
return false;
|
|
|
|
|
|
// copy the data to the output data buffer
|
|
for(int i = 1; i < length + 1; i++)
|
|
{
|
|
data[i-1] = tmpData[i];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* BRIEF: Receive data from the selected slave over SPI without *
|
|
* requesting from what register i.e. just listen if a slave has *
|
|
* something to say *
|
|
* INFORMATION: By passing in a register we can request specified *
|
|
* data over the SPI bus *
|
|
***********************************************************************/
|
|
bool spi_receive(spi_profile *profile,
|
|
uint8_t *data,
|
|
uint32_t length,
|
|
uint32_t timeout_ms)
|
|
{
|
|
HAL_StatusTypeDef err; /* SPI transmission status variable */
|
|
|
|
// Tell the selected slave that the data is intended for him/her (hen)
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_RESET);
|
|
// Receive data if available from the slave
|
|
err = HAL_SPI_Receive(profile->profile, data, length, timeout_ms);
|
|
// Tell the selected slave that we are done for now
|
|
HAL_GPIO_WritePin(profile->spi_nss_port, profile->spi_nss, GPIO_PIN_SET);
|
|
|
|
return (err == HAL_OK);
|
|
}
|