mirror of https://github.com/ARMmbed/mbed-os.git
[NUCLEO_F030R8] Add SPI api, corrections in I2C
parent
08941aaba1
commit
ca173a1867
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue