[NUCLEO_F030R8] Add SPI api, corrections in I2C

pull/158/head
bcostm 2014-01-30 15:29:07 +01:00
parent 08941aaba1
commit ca173a1867
3 changed files with 307 additions and 63 deletions

View File

@ -44,7 +44,7 @@
#define DEVICE_I2C 1
#define DEVICE_I2CSLAVE 0
#define DEVICE_SPI 0
#define DEVICE_SPI 1
#define DEVICE_SPISLAVE 0
#define DEVICE_RTC 1

View File

@ -42,12 +42,12 @@
#define LONG_TIMEOUT ((int)0x8000)
static const PinMap PinMap_I2C_SDA[] = {
{PB_9, I2C_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_OD, GPIO_PuPd_NOPULL, GPIO_AF_1)},
{PB_9, I2C_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_OD, GPIO_PuPd_UP, GPIO_AF_1)},
{NC, NC, 0}
};
static const PinMap PinMap_I2C_SCL[] = {
{PB_8, I2C_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_OD, GPIO_PuPd_NOPULL, GPIO_AF_1)},
{PB_8, I2C_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_OD, GPIO_PuPd_UP, GPIO_AF_1)},
{NC, NC, 0}
};
@ -71,10 +71,10 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
//}
// Configure I2C pins
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
pin_mode(sda, OpenDrain);
pin_mode(scl, OpenDrain);
pinmap_pinout(sda, PinMap_I2C_SDA);
pin_mode(sda, OpenDrain);
// Reset to clear pending flags if any
i2c_reset(obj);
@ -120,12 +120,15 @@ void i2c_frequency(i2c_t *obj, int hz) {
inline int i2c_start(i2c_t *obj) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
int timeout = LONG_TIMEOUT;
int timeout;
// Test BUSY Flag
while (I2C_GetFlagStatus(i2c, I2C_ISR_BUSY) != RESET)
{
if ((timeout--) == 0) return 0;
timeout = LONG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_BUSY) != RESET) {
timeout--;
if (timeout == 0) {
return 0;
}
}
I2C_GenerateSTART(i2c, ENABLE);
@ -135,27 +138,21 @@ inline int i2c_start(i2c_t *obj) {
inline int i2c_stop(i2c_t *obj) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
I2C_GenerateSTOP(i2c, ENABLE);
return 0;
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
int timeout;
int count;
int value;
if (length == 0) return 0;
// Configure slave address, nbytes, reload, end mode and start or stop generation
if (stop) {
I2C_TransferHandling(i2c, address, length, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
}
else {
I2C_TransferHandling(i2c, address, length, I2C_Reload_Mode, I2C_Generate_Start_Read);
}
I2C_TransferHandling(i2c, address, length, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
// Read all bytes
for (count = 0; count < length; count++) {
@ -163,40 +160,25 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
data[count] = (char)value;
}
if (stop) {
// Wait until STOPF flag is set
timeout = LONG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_STOPF) == RESET)
{
if ((timeout--) == 0) return 0;
}
// Clear STOPF flag
I2C_ClearFlag(i2c, I2C_ICR_STOPCF);
}
return length;
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
int timeout;
//int timeout;
int count;
if (length == 0) return 0;
// TODO: the stop is always sent even with I2C_SoftEnd_Mode. To be corrected.
// Test BUSY Flag
//timeout = LONG_TIMEOUT;
//while (I2C_GetFlagStatus(i2c, I2C_ISR_BUSY) != RESET)
//{
// if((timeout--) == 0) return 0;
//}
// Configure slave address, nbytes, reload, end mode and start or stop generation
if (stop) {
//if (stop) {
I2C_TransferHandling(i2c, address, length, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);
}
else {
I2C_TransferHandling(i2c, address, length, I2C_Reload_Mode, I2C_Generate_Start_Write);
}
//}
//else {
// I2C_TransferHandling(i2c, address, length, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
//}
// Write all bytes
for (count = 0; count < length; count++) {
@ -206,17 +188,20 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
}
}
/*
if (stop) {
// Wait until STOPF flag is set
timeout = LONG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_STOPF) == RESET)
{
if ((timeout--) == 0) return 0;
}
while (I2C_GetFlagStatus(i2c, I2C_ISR_STOPF) == RESET) {
timeout--;
if (timeout == 0) {
return 0;
}
}
// Clear STOPF flag
I2C_ClearFlag(i2c, I2C_ICR_STOPCF);
}
*/
return count;
}
@ -224,11 +209,15 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
int i2c_byte_read(i2c_t *obj, int last) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
uint8_t data;
int timeout = FLAG_TIMEOUT;
int timeout;
// Wait until the byte is received
timeout = FLAG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_RXNE) == RESET) {
if ((timeout--) == 0) return 0;
timeout--;
if (timeout == 0) {
return 0;
}
}
data = I2C_ReceiveData(i2c);
@ -238,21 +227,18 @@ int i2c_byte_read(i2c_t *obj, int last) {
int i2c_byte_write(i2c_t *obj, int data) {
I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
int timeout = FLAG_TIMEOUT;
int timeout;
// Wait until TXIS flag is set
timeout = LONG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_TXIS) == RESET)
{
if ((timeout--) == 0) return 0;
// Wait until the previous byte is transmitted
timeout = FLAG_TIMEOUT;
while (I2C_GetFlagStatus(i2c, I2C_ISR_TXIS) == RESET) {
timeout--;
if (timeout == 0) {
return 0;
}
}
I2C_SendData(i2c, (uint8_t)data);
// Wait until the byte is transmitted
//while (I2C_GetFlagStatus(i2c, I2C_ISR_TCR) == RESET) {
// if ((timeout--) == 0) return 0;
//}
return 1;
}

View File

@ -0,0 +1,258 @@
/* mbed Microcontroller Library
*******************************************************************************
* Copyright (c) 2014, STMicroelectronics
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
*/
#include "spi_api.h"
#if DEVICE_SPI
#include <math.h>
#include "cmsis.h"
#include "pinmap.h"
#include "error.h"
static const PinMap PinMap_SPI_MOSI[] = {
{PA_7, SPI_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_0)},
{NC, NC, 0}
};
static const PinMap PinMap_SPI_MISO[] = {
{PA_6, SPI_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_0)},
{NC, NC, 0}
};
static const PinMap PinMap_SPI_SCLK[] = {
{PA_5, SPI_1, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_0)},
{NC, NC, 0}
};
// Only used in Slave mode
static const PinMap PinMap_SPI_SSEL[] = {
{PB_6, SPI_1, STM_PIN_DATA(GPIO_Mode_IN, GPIO_OType_PP, GPIO_PuPd_NOPULL, 0)}, // Generic IO, not real H/W NSS pin
{NC, NC, 0}
};
static void init_spi(spi_t *obj) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
SPI_InitTypeDef SPI_InitStructure;
SPI_Cmd(spi, DISABLE);
SPI_InitStructure.SPI_Mode = obj->mode;
SPI_InitStructure.SPI_NSS = obj->nss;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_DataSize = obj->bits;
SPI_InitStructure.SPI_CPOL = obj->cpol;
SPI_InitStructure.SPI_CPHA = obj->cpha;
SPI_InitStructure.SPI_BaudRatePrescaler = obj->br_presc;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(spi, &SPI_InitStructure);
SPI_RxFIFOThresholdConfig(spi, SPI_RxFIFOThreshold_QF);
SPI_Cmd(spi, ENABLE);
}
void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
// Determine the SPI to use
SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
obj->spi = (SPIName)pinmap_merge(spi_data, spi_cntl);
if (obj->spi == (SPIName)NC) {
error("SPI pinout mapping failed");
}
// Enable SPI clock
if (obj->spi == SPI_1) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
}
if (obj->spi == SPI_2) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
}
// Configure the SPI pins
pinmap_pinout(mosi, PinMap_SPI_MOSI);
pinmap_pinout(miso, PinMap_SPI_MISO);
pinmap_pinout(sclk, PinMap_SPI_SCLK);
// Save new values
obj->bits = SPI_DataSize_8b;
obj->cpol = SPI_CPOL_Low;
obj->cpha = SPI_CPHA_1Edge;
obj->br_presc = SPI_BaudRatePrescaler_8; // 1 MHz
if (ssel == NC) { // Master
obj->mode = SPI_Mode_Master;
obj->nss = SPI_NSS_Soft;
}
else { // Slave
pinmap_pinout(ssel, PinMap_SPI_SSEL);
obj->mode = SPI_Mode_Slave;
obj->nss = SPI_NSS_Soft;
}
init_spi(obj);
}
void spi_free(spi_t *obj) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
SPI_I2S_DeInit(spi);
}
void spi_format(spi_t *obj, int bits, int mode, int slave) {
// Save new values
if (bits == 8) {
obj->bits = SPI_DataSize_8b;
}
else {
obj->bits = SPI_DataSize_16b;
}
switch (mode) {
case 0:
obj->cpol = SPI_CPOL_Low;
obj->cpha = SPI_CPHA_1Edge;
break;
case 1:
obj->cpol = SPI_CPOL_Low;
obj->cpha = SPI_CPHA_2Edge;
break;
case 2:
obj->cpol = SPI_CPOL_High;
obj->cpha = SPI_CPHA_1Edge;
break;
default:
obj->cpol = SPI_CPOL_High;
obj->cpha = SPI_CPHA_2Edge;
break;
}
if (slave == 0) {
obj->mode = SPI_Mode_Master;
obj->nss = SPI_NSS_Soft;
}
else {
obj->mode = SPI_Mode_Slave;
obj->nss = SPI_NSS_Hard;
}
init_spi(obj);
}
void spi_frequency(spi_t *obj, int hz) {
// Get SPI clock frequency
uint32_t PCLK = SystemCoreClock;
// Choose the baud rate divisor (between 2 and 256)
uint32_t divisor = PCLK / hz;
// Find the nearest power-of-2
divisor = (divisor > 0 ? divisor-1 : 0);
divisor |= divisor >> 1;
divisor |= divisor >> 2;
divisor |= divisor >> 4;
divisor |= divisor >> 8;
divisor |= divisor >> 16;
divisor++;
uint32_t baud_rate = __builtin_ffs(divisor) - 2;
// Save new value
obj->br_presc = ((baud_rate > 7) ? (7 << 3) : (baud_rate << 3));
init_spi(obj);
}
static inline int ssp_readable(spi_t *obj) {
int status;
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
// Check if data is received
status = ((SPI_I2S_GetFlagStatus(spi, SPI_I2S_FLAG_RXNE) != RESET) ? 1 : 0);
return status;
}
static inline int ssp_writeable(spi_t *obj) {
int status;
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
// Check if data is transmitted
status = ((SPI_I2S_GetFlagStatus(spi, SPI_I2S_FLAG_TXE) != RESET) ? 1 : 0);
return status;
}
static inline void ssp_write(spi_t *obj, int value) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
while (!ssp_writeable(obj));
SPI_SendData8(spi, (uint8_t)value);
}
static inline int ssp_read(spi_t *obj) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
while (!ssp_readable(obj));
return (int)SPI_ReceiveData8(spi);
}
static inline int ssp_busy(spi_t *obj) {
int status;
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
status = ((SPI_I2S_GetFlagStatus(spi, SPI_I2S_FLAG_BSY) != RESET) ? 1 : 0);
return status;
}
int spi_master_write(spi_t *obj, int value) {
ssp_write(obj, value);
return ssp_read(obj);
}
int spi_slave_receive(spi_t *obj) {
return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
};
int spi_slave_read(spi_t *obj) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
return (int)SPI_ReceiveData8(spi);
}
void spi_slave_write(spi_t *obj, int value) {
SPI_TypeDef *spi = (SPI_TypeDef *)(obj->spi);
while (!ssp_writeable(obj));
SPI_SendData8(spi, (uint8_t)value);
}
int spi_busy(spi_t *obj) {
return ssp_busy(obj);
}
#endif