This repository has been archived on 2020-06-14. You can view files and clone it, but cannot push or open issues or pull requests.
Lennart Eriksson dca3a03ab9 Small fixes
2016-10-06 10:45:16 +02:00

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