Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • avn/swd/skyward-boardcore
  • emilio.corigliano/skyward-boardcore
  • ettore.pane/skyward-boardcore
  • giulia.facchi/skyward-boardcore
  • valerio.flamminii/skyward-boardcore
  • nicolo.caruso/skyward-boardcore
6 results
Select Git revision
Show changes
Commits on Source (5)
......@@ -259,7 +259,6 @@ def check_find(directory):
sum = find_in_code(directory, r'^using namespace', '.h')
sum += find_in_code(directory,
r'[^a-zA-Z0-9]printf\(', pathFilter='shared')
sum += find_in_code(directory, r'( |^)assert\(')
sum += find_in_code(directory, '^ *throw ', pathFilter='catch')
if sum > 0:
......
......@@ -32,39 +32,163 @@ I2C::I2C(I2C_TypeDef *i2c, const miosix::GpioPin &scl,
}
bool I2C::read(const I2CDriver::I2CSlaveConfig &slaveConfig, void *buffer,
const size_t &nBytes)
const size_t nBytes)
{
i2c.flushBus();
return i2c.read(slaveConfig, buffer, nBytes);
}
bool I2C::write(const I2CDriver::I2CSlaveConfig &slaveConfig,
const void *buffer, const size_t &nBytes)
const void *buffer, const size_t nBytes)
{
i2c.flushBus();
return i2c.write(slaveConfig, buffer, nBytes);
}
bool I2C::readRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, uint8_t &registerContent)
const uint8_t registerAddress, uint8_t &registerContent)
{
i2c.flushBus();
return i2c.write(slaveConfig, &registerAddress, 1, false) &&
i2c.read(slaveConfig, &registerContent, 1);
}
bool I2C::readRegister16(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint16_t &registerContent)
{
i2c.flushBus();
uint8_t buf[2] = {0};
if (i2c.write(slaveConfig, &registerAddress, 1, false) &&
i2c.read(slaveConfig, buf, 2))
{
registerContent =
(slaveConfig.MSBFirst ? ((uint16_t)buf[0]) << 8 | buf[1]
: ((uint16_t)buf[1]) << 8 | buf[0]);
return true;
}
return false;
}
bool I2C::readRegister24(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint32_t &registerContent)
{
i2c.flushBus();
uint8_t buf[3] = {0};
if (i2c.write(slaveConfig, &registerAddress, 1, false) &&
i2c.read(slaveConfig, buf, 3))
{
registerContent =
(slaveConfig.MSBFirst
? ((uint32_t)buf[0]) << 16 | ((uint32_t)buf[1] << 8) | buf[2]
: ((uint32_t)buf[2]) << 16 | ((uint32_t)buf[1] << 8) | buf[0]);
return true;
}
return false;
}
bool I2C::readRegister32(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint32_t &registerContent)
{
i2c.flushBus();
uint8_t buf[4] = {0};
if (i2c.write(slaveConfig, &registerAddress, 1, false) &&
i2c.read(slaveConfig, buf, 4))
{
registerContent =
(slaveConfig.MSBFirst
? ((uint32_t)buf[0]) << 24 | ((uint32_t)buf[1] << 16) |
((uint32_t)buf[2] << 8) | buf[3]
: ((uint32_t)buf[3]) << 24 | ((uint32_t)buf[2] << 16) |
((uint32_t)buf[1] << 8) | buf[0]);
return true;
}
return false;
}
bool I2C::writeRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress,
const uint8_t &registerContent)
const uint8_t registerAddress,
const uint8_t registerContent)
{
const uint8_t reg[2] = {registerAddress, registerContent};
i2c.flushBus();
return i2c.write(slaveConfig, reg, 2);
}
bool I2C::writeRegister16(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint16_t registerContent)
{
i2c.flushBus();
if (slaveConfig.MSBFirst)
{
const uint8_t reg[3] = {registerAddress, // subAddr
(uint8_t)(registerContent >> 8), // MSB
(uint8_t)(registerContent)}; // LSB
return i2c.write(slaveConfig, reg, 3);
}
else
{
const uint8_t reg[3] = {registerAddress, // subAddr
(uint8_t)(registerContent), // LSB
(uint8_t)(registerContent >> 8)}; // MSB
return i2c.write(slaveConfig, reg, 3);
}
}
bool I2C::writeRegister24(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint32_t registerContent)
{
i2c.flushBus();
if (slaveConfig.MSBFirst)
{
const uint8_t reg[4] = {registerAddress, // subAddr
(uint8_t)(registerContent >> 16), // MSB
(uint8_t)(registerContent >> 8), //
(uint8_t)registerContent}; // LSB
return i2c.write(slaveConfig, reg, 4);
}
else
{
const uint8_t reg[4] = {registerAddress, // subAddr
(uint8_t)(registerContent), // LSB
(uint8_t)(registerContent >> 8), //
(uint8_t)(registerContent >> 16)}; // MSB
return i2c.write(slaveConfig, reg, 4);
}
}
bool I2C::writeRegister32(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint32_t registerContent)
{
i2c.flushBus();
if (slaveConfig.MSBFirst)
{
const uint8_t reg[5] = {registerAddress, // subAddr
(uint8_t)(registerContent >> 24), // MSB
(uint8_t)(registerContent >> 16), //
(uint8_t)(registerContent >> 8), //
(uint8_t)registerContent}; // LSB
return i2c.write(slaveConfig, reg, 5);
}
else
{
const uint8_t reg[5] = {registerAddress, // subAddr
(uint8_t)(registerContent), // LSB
(uint8_t)(registerContent >> 8), //
(uint8_t)(registerContent >> 16), //
(uint8_t)(registerContent >> 24)}; // MSB
return i2c.write(slaveConfig, reg, 5);
}
}
bool I2C::readFromRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, void *buffer,
const size_t &nBytes)
const uint8_t registerAddress, void *buffer,
const size_t nBytes)
{
i2c.flushBus();
return i2c.write(slaveConfig, &registerAddress, 1, false) &&
......@@ -86,38 +210,86 @@ SyncedI2C::SyncedI2C(I2C_TypeDef *i2c, const miosix::GpioPin &scl,
}
bool SyncedI2C::read(const I2CDriver::I2CSlaveConfig &slaveConfig, void *buffer,
const size_t &nBytes)
const size_t nBytes)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::read(slaveConfig, buffer, nBytes);
}
bool SyncedI2C::write(const I2CDriver::I2CSlaveConfig &slaveConfig,
const void *buffer, const size_t &nBytes)
const void *buffer, const size_t nBytes)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::write(slaveConfig, buffer, nBytes);
}
bool SyncedI2C::readRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress,
const uint8_t registerAddress,
uint8_t &registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::readRegister(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::readRegister16(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint16_t &registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::readRegister16(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::readRegister24(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint32_t &registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::readRegister24(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::readRegister32(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
uint32_t &registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::readRegister32(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::writeRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress,
const uint8_t &registerContent)
const uint8_t registerAddress,
const uint8_t registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::writeRegister(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::writeRegister16(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint16_t registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::writeRegister16(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::writeRegister24(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint32_t registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::writeRegister24(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::writeRegister32(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress,
const uint32_t registerContent)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::writeRegister32(slaveConfig, registerAddress, registerContent);
}
bool SyncedI2C::readFromRegister(const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, void *buffer,
const size_t &nBytes)
const uint8_t registerAddress, void *buffer,
const size_t nBytes)
{
miosix::Lock<miosix::FastMutex> lock(mutex);
return I2C::readFromRegister(slaveConfig, registerAddress, buffer, nBytes);
......
......@@ -71,7 +71,7 @@ public:
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool read(const I2CDriver::I2CSlaveConfig &slaveConfig,
void *buffer, const size_t &nBytes);
void *buffer, const size_t nBytes);
/**
* @brief Non blocking write operation to write nBytes.
......@@ -86,10 +86,10 @@ public:
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool write(const I2CDriver::I2CSlaveConfig &slaveConfig,
const void *buffer, const size_t &nBytes);
const void *buffer, const size_t nBytes);
/**
* @brief Non blocking operation to read a 1-byte register from a slave.
* @brief Non blocking operation to read an 8-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
......@@ -102,10 +102,58 @@ public:
*/
[[nodiscard]] bool readRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, uint8_t &registerContent);
const uint8_t registerAddress, uint8_t &registerContent);
/**
* @brief Non blocking operation to write a 1-byte register from a slave.
* @brief Non blocking operation to read a 16-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister16(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint16_t &registerContent);
/**
* @brief Non blocking operation to read a 24-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister24(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint32_t &registerContent);
/**
* @brief Non blocking operation to read a 32-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister32(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint32_t &registerContent);
/**
* @brief Non blocking operation to write an 8-bit register from a slave.
*
* This method, if necessary, flushes the bus before the write operation is
* performed. In case of an error during the communication, this method
......@@ -118,7 +166,55 @@ public:
*/
[[nodiscard]] bool writeRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, const uint8_t &registerContent);
const uint8_t registerAddress, const uint8_t registerContent);
/**
* @brief Non blocking operation to write a 16-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister16(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint16_t registerContent);
/**
* @brief Non blocking operation to write a 24-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister24(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint32_t registerContent);
/**
* @brief Non blocking operation to write a 32-bit register from a slave.
*
* This method, if necessary, flushes the bus before the read operation is
* performed. In case of an error during the communication, this method
* returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister32(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint32_t registerContent);
/**
* @brief Non blocking operation to read n-bytes from register from a slave.
......@@ -135,7 +231,7 @@ public:
*/
[[nodiscard]] bool readFromRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, void *buffer, const size_t &nBytes);
const uint8_t registerAddress, void *buffer, const size_t nBytes);
/**
* @brief Non blocking operation to check if a slave is available.
......@@ -200,7 +296,7 @@ public:
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool read(const I2CDriver::I2CSlaveConfig &slaveConfig,
void *buffer, const size_t &nBytes);
void *buffer, const size_t nBytes);
/**
* @brief Write operation to write nBytes.
......@@ -215,10 +311,10 @@ public:
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool write(const I2CDriver::I2CSlaveConfig &slaveConfig,
const void *buffer, const size_t &nBytes);
const void *buffer, const size_t nBytes);
/**
* @brief Read a one-byte register from the device.
* @brief Read an 8-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
......@@ -231,10 +327,58 @@ public:
*/
[[nodiscard]] bool readRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, uint8_t &registerContent);
const uint8_t registerAddress, uint8_t &registerContent);
/**
* @brief Write a one-byte register from the device.
* @brief Read a 16-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister16(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint16_t &registerContent);
/**
* @brief Read a 24-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister24(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint32_t &registerContent);
/**
* @brief Read a 32-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent Where to store the content of the register.
* @returns True if the read is successful, false otherwise.
*/
[[nodiscard]] bool readRegister32(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, uint32_t &registerContent);
/**
* @brief Write an 8-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
......@@ -247,7 +391,55 @@ public:
*/
[[nodiscard]] bool writeRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, const uint8_t &registerContent);
const uint8_t registerAddress, const uint8_t registerContent);
/**
* @brief Write a 16-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister16(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint16_t registerContent);
/**
* @brief Write a 24-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister24(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint32_t registerContent);
/**
* @brief Write a 32-bit register from the device.
*
* This method could have to wait that no other thread is trying to do some
* operation on the bus. In case of an error during the communication, this
* method returns false immediately.
* @warning Check always if the operation succeeded or not!
* @param slaveConfig The configuration struct of the slave device.
* @param registerAddress Byte that represents the address of the register.
* @param registerContent The content to write on the register.
* @returns True if the write is successful, false otherwise.
*/
[[nodiscard]] bool writeRegister32(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t registerAddress, const uint32_t registerContent);
/**
* @brief Read n-bytes from register from a slave.
......@@ -264,7 +456,7 @@ public:
*/
[[nodiscard]] bool readFromRegister(
const I2CDriver::I2CSlaveConfig &slaveConfig,
const uint8_t &registerAddress, void *buffer, const size_t &nBytes);
const uint8_t registerAddress, void *buffer, const size_t nBytes);
/**
* @brief Check if a slave is available.
......
......@@ -108,6 +108,8 @@ public:
///< addressing |6-bit unused|10-bit address|).
I2CDriver::Addressing addressing; ///< Addressing mode of the device.
I2CDriver::Speed speed; ///< Speed mode of the communication.
bool MSBFirst; ///< Registers with lower values are the MSB of
///< multi-byte registers
} I2CSlaveConfig;
/**
......
......@@ -22,6 +22,7 @@
#pragma once
#include <assert.h>
#include <interfaces/delays.h>
#include <utils/ClockUtils.h>
......@@ -489,6 +490,9 @@ inline void SPIBus::read(uint8_t* data, size_t nBytes)
inline void SPIBus::read16(uint16_t* data, size_t nBytes)
{
// At the start of the transfer we assume that the RX FIFO is empty
assert((spi->SR & SPI_SR_RXNE) == 0);
// Set 16 bit frame format
set16BitFrameFormat();
......@@ -529,6 +533,9 @@ inline void SPIBus::write(const uint8_t* data, size_t nBytes)
inline void SPIBus::write16(const uint16_t* data, size_t nBytes)
{
// At the start of the transfer we assume that the RX FIFO is empty
assert((spi->SR & SPI_SR_RXNE) == 0);
// Set 16 bit frame format
set16BitFrameFormat();
......@@ -555,12 +562,15 @@ inline void SPIBus::write16(const uint16_t* data, size_t nBytes)
inline uint8_t SPIBus::transfer(uint8_t data)
{
// At the start of the transfer we assume that the RX FIFO is empty
assert((spi->SR & SPI_SR_RXNE) == 0);
// Wait until the peripheral is ready to transmit
while ((spi->SR & SPI_SR_TXE) == 0)
;
// Write the data item to transmit
spi->DR = static_cast<uint8_t>(data);
*(volatile uint8_t*)&spi->DR = static_cast<uint8_t>(data);
// Wait until data is received
while ((spi->SR & SPI_SR_RXNE) == 0)
......@@ -572,6 +582,9 @@ inline uint8_t SPIBus::transfer(uint8_t data)
inline uint16_t SPIBus::transfer16(uint16_t data)
{
// At the start of the transfer we assume that the RX FIFO is empty
assert((spi->SR & SPI_SR_RXNE) == 0);
// Set 16 bit frame format
set16BitFrameFormat();
......@@ -586,11 +599,13 @@ inline uint16_t SPIBus::transfer16(uint16_t data)
while ((spi->SR & SPI_SR_RXNE) == 0)
;
// Read the received data item
data = static_cast<uint16_t>(spi->DR);
// Go back to 8 bit frame format
set8BitFrameFormat();
// Read the received data item
return static_cast<uint16_t>(spi->DR);
return data;
}
inline uint32_t SPIBus::transfer24(uint32_t data)
......@@ -617,6 +632,9 @@ inline void SPIBus::transfer(uint8_t* data, size_t nBytes)
inline void SPIBus::transfer16(uint16_t* data, size_t nBytes)
{
// At the start of the transfer we assume that the RX FIFO is empty
assert((spi->SR & SPI_SR_RXNE) == 0);
// Set 16 bit frame format
set16BitFrameFormat();
......