Split in two. First, the platform specific hardware config:
async command msp430_i2c_union_config_t* getConfig();
typedef struct {
unsigned int mst: 1; //Master mode (0=slave; 1=master)
unsigned int listen: 1; //Listen enable (0=disabled; 1=enabled, feed tx back to receiver)
unsigned int xa: 1; //Extended addressing (0=7-bit addressing; 1=8-bit addressing)
unsigned int txdmaen: 1; //DMA to TX (0=disabled; 1=enabled)
unsigned int rxdmaen: 1; //RX to DMA (0=disabled; 1=enabled)
unsigned int i2cssel: 2; //Clock source (00=disabled; 01=ACLK; 10=SMCLK; 11=SMCLK)
unsigned int i2crm: 1; //Repeat mode (0=use I2CNDAT; 1=count in software)
unsigned int i2cword: 1; //Word mode (0=byte mode; 1=word mode)
unsigned int i2cpsc: 8; //Clock prescaler (values >0x04 not recomended)
unsigned int i2csclh: 8; //High period (high period=[value+2]*i2cpsc; can not be lower than 5*i2cpsc)
unsigned int i2cscll: 8; //Low period (low period=[value+2]*i2cpsc; can not be lower than 5*i2cpsc)
unsigned int i2coa : 10; // Own address register.
} msp430_i2c_config_t;
and the general I2CPacket interface, templated over the address size:
async command error_t read(flags, addr, length, data);
async command error_t write(flags, addr, length, data);
// callbacks
async event void readDone(error, addr, length, data);
async event void writeDone(error, addr, length, data);
Their interface is very low level. Basically, there is a C function for every I2C configuration parameter or function.
void I2C_Init(i2c, initParams);
void I2C_Cmd(i2c, state);
I2C_ITConfig(i2c, interrupts, state);
I2C_StretchClockCmd(i2c, state);
...
void I2C_SendData(i2c, byte);
I think they also realize this, and created a layer on top of I2C for writing applications.
u32 CPAL_I2C_Init(initParams);
u32 CPAL_I2C_Read(initParams);
u32 CPAL_I2C_Write(initParams);
// Callbacks
void CPAL_I2C_RXTC_UserCallback(initParams); // after received data
...
All RX and TX buffers are specified as a part of the struct
(initParams
) that is passed to each function.
But of course even those are nested another
struct deep.
typedef struct {
CPAL_DevTypeDef CPAL_Dev;
CPAL_DirectionTypeDef CPAL_Direction; /*!<Specifies the direction for the device transfers. */
CPAL_ModeTypeDef CPAL_Mode; /*!<Specifies the maser/slave mode of device. It can be one of the */
CPAL_ProgModelTypeDef CPAL_ProgModel; /*!<Specifies the programming model for the device transfers. */
CPAL_TransferTypeDef* pCPAL_TransferTx; /*!<Pointer on a structure specifying the parameters of the current */
CPAL_TransferTypeDef* pCPAL_TransferRx; /*!<Pointer on a structure specifying the parameters of the current */
__IO CPAL_StateTypeDef CPAL_State; /*!<Holds the current State of the CPAL driver relative to the device */
__IO uint32_t wCPAL_DevError; /*!<Specifies the error code for the current operation.The error codes */
uint32_t wCPAL_Options; /*!<Bit-field value specifying additional options for the configuration */
__IO uint32_t wCPAL_Timeout; /*!<This field is with timeout procedure. its used to detect timeout */
I2C_InitTypeDef* pCPAL_I2C_Struct; /*!<Pointer to a device Initialization structure as described */
} initParams;
Only master mode.
int nrf_drv_twi_init(instance, config, event_handler);
void nrf_drv_twi_enable(instance);
void nrf_drv_twi_disable(instance);
int nrf_drv_twi_tx(instance, address, data, length, xfer_pending);
int nrf_drv_twi_rx(instance, address, data, length, xfer_pending);
This one is pretty nice. Note: in init, event handler can be NULL and the driver will use blocking calls.
pub trait I2C {
// No magic here
fn enable (&mut self);
fn disable (&mut self);
// Switch into slave mode
fn set_slave_mode(&mut self, address: u16);
// Switch into master mode
fn set_master_mod(&mut self);
// Master Mode
fn write (&mut self, flags, addr: u16, data: &[u8], done);
fn read (&mut self, flags, addr: u16, data: &[u8], done);
// Slave Mode
fn wait (&mut self, tx: &[u8], rx: &mut[u8], done);
}
Then of course there is the initial init which comes from the device tree.
interface Random {
async command uint32_t rand32();
async command uint16_t rand16();
}
int nrf_drv_rng_bytes_available(uint8_t* p_bytes_available);
int nrf_drv_rng_pool_capacity(uint8_t * p_pool_capacity);
// Gets a pointer to a buffer of random numbers
int nrf_drv_rng_rand(uint8_t * p_buff, uint8_t length);
pub trait RNG {
/// Read a 32 bit random number.
fn read (&mut self, done);
/// Read multiple 32 bit random numbers.
fn read_multiple (&mut self, count: usize, vals: &mut[u32], done);
}