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