mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-22 04:19:12 +00:00
415 lines
14 KiB
C
415 lines
14 KiB
C
/******************************************************************************
|
|
* The MIT License
|
|
*
|
|
* Copyright (c) 2010 Perry Hung.
|
|
* Copyright (c) 2012 LeafLabs, LLC.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
* @file libmaple/include/libmaple/i2c.h
|
|
* @brief Inter-Integrated Circuit (I2C) peripheral support
|
|
*
|
|
* Currently master-only. Usage notes:
|
|
*
|
|
* - Enable an I2C device with i2c_master_enable().
|
|
* - Initialize an array of struct i2c_msg to suit the bus
|
|
* transactions (reads/writes) you wish to perform.
|
|
* - Call i2c_master_xfer() to do the work.
|
|
*/
|
|
|
|
#ifndef _LIBMAPLE_I2C_H_
|
|
#define _LIBMAPLE_I2C_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*
|
|
* Series header must provide:
|
|
*
|
|
* - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in
|
|
* MHz. (This is for internal use only).
|
|
*
|
|
* - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1.
|
|
* This is for internal use only. It's a hack to work around a
|
|
* silicon bug related to I2C IRQ pre-emption on some targets. If 1,
|
|
* the series header must also declare and implement a routine with
|
|
* this signature (it may also be provided as a macro):
|
|
*
|
|
* void _i2c_irq_priority_fixup(i2c_dev*)
|
|
*
|
|
* This will be called by i2c_enable_irq() before actually enabling
|
|
* I2C interrupts.
|
|
*
|
|
* - Reg. map base pointers, device pointer declarations.
|
|
*/
|
|
|
|
/* Roger clark. Replaced with line below #include <series/i2c.h>*/
|
|
#include "stm32f1/include/series/i2c.h"
|
|
#include <libmaple/i2c_common.h>
|
|
|
|
#include <libmaple/libmaple_types.h>
|
|
#include <libmaple/rcc.h>
|
|
#include <libmaple/nvic.h>
|
|
#include <libmaple/gpio.h>
|
|
|
|
/** I2C register map type */
|
|
typedef struct i2c_reg_map {
|
|
__io uint32 CR1; /**< Control register 1 */
|
|
__io uint32 CR2; /**< Control register 2 */
|
|
__io uint32 OAR1; /**< Own address register 1 */
|
|
__io uint32 OAR2; /**< Own address register 2 */
|
|
__io uint32 DR; /**< Data register */
|
|
__io uint32 SR1; /**< Status register 1 */
|
|
__io uint32 SR2; /**< Status register 2 */
|
|
__io uint32 CCR; /**< Clock control register */
|
|
__io uint32 TRISE; /**< TRISE (rise time) register */
|
|
} i2c_reg_map;
|
|
|
|
/**
|
|
* @brief I2C message type
|
|
*/
|
|
typedef struct i2c_msg {
|
|
uint16 addr; /**< Address */
|
|
|
|
#define I2C_MSG_READ 0x1
|
|
#define I2C_MSG_10BIT_ADDR 0x2
|
|
/**
|
|
* Bitwise OR of:
|
|
* - I2C_MSG_READ (write is default)
|
|
* - I2C_MSG_10BIT_ADDR (7-bit is default) */
|
|
uint16 flags;
|
|
|
|
uint16 length; /**< Message length */
|
|
uint16 xferred; /**< Messages transferred */
|
|
uint8 *data; /**< Data */
|
|
} i2c_msg;
|
|
|
|
/*
|
|
* Register bit definitions
|
|
*/
|
|
|
|
/* Control register 1 */
|
|
|
|
#define I2C_CR1_SWRST (1U << 15) // Software reset
|
|
#define I2C_CR1_ALERT (1U << 13) // SMBus alert
|
|
#define I2C_CR1_PEC (1U << 12) // Packet error checking
|
|
#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position
|
|
#define I2C_CR1_ACK (1U << 10) // Acknowledge enable
|
|
#define I2C_CR1_STOP (1U << 9) // Stop generation
|
|
#define I2C_CR1_START (1U << 8) // Start generation
|
|
#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable
|
|
#define I2C_CR1_ENGC (1U << 6) // General call enable
|
|
#define I2C_CR1_ENPEC (1U << 5) // PEC enable
|
|
#define I2C_CR1_ENARP (1U << 4) // ARP enable
|
|
#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type
|
|
#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device
|
|
#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host
|
|
#define I2C_CR1_SMBUS (1U << 1) // SMBus mode
|
|
#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C
|
|
#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus
|
|
#define I2C_CR1_PE (1U << 0) // Peripheral Enable
|
|
|
|
/* Control register 2 */
|
|
|
|
#define I2C_CR2_LAST (1U << 12) // DMA last transfer
|
|
#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable
|
|
#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable
|
|
#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable
|
|
#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable
|
|
#define I2C_CR2_FREQ 0x3F // Peripheral input frequency
|
|
|
|
/* Own address register 1 */
|
|
|
|
#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode
|
|
#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit
|
|
#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit
|
|
#define I2C_OAR1_ADD 0x3FF // Interface address
|
|
|
|
/* Own address register 2 */
|
|
|
|
#define I2C_OAR2_ADD2 0xFE // Interface address
|
|
#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable
|
|
|
|
/* Status register 1 */
|
|
|
|
#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert
|
|
#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error
|
|
#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception
|
|
#define I2C_SR1_OVR (1U << 11) // Overrun/underrun
|
|
#define I2C_SR1_AF (1U << 10) // Acknowledge failure
|
|
#define I2C_SR1_ARLO (1U << 9) // Arbitration lost
|
|
#define I2C_SR1_BERR (1U << 8) // Bus error
|
|
#define I2C_SR1_TXE (1U << 7) // Data register empty
|
|
#define I2C_SR1_RXNE (1U << 6) // Data register not empty
|
|
#define I2C_SR1_STOPF (1U << 4) // Stop detection
|
|
#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent
|
|
#define I2C_SR1_BTF (1U << 2) // Byte transfer finished
|
|
#define I2C_SR1_ADDR (1U << 1) // Address sent/matched
|
|
#define I2C_SR1_SB (1U << 0) // Start bit
|
|
|
|
/* Status register 2 */
|
|
|
|
#define I2C_SR2_PEC 0xFF00 // Packet error checking register
|
|
#define I2C_SR2_DUALF (1U << 7) // Dual flag
|
|
#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header
|
|
#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address
|
|
#define I2C_SR2_GENCALL (1U << 4) // General call address
|
|
#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver
|
|
#define I2C_SR2_BUSY (1U << 1) // Bus busy
|
|
#define I2C_SR2_MSL (1U << 0) // Master/slave
|
|
|
|
/* Clock control register */
|
|
|
|
#define I2C_CCR_FS (1U << 15) // Fast mode selection
|
|
#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle
|
|
#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1
|
|
#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9
|
|
#define I2C_CCR_CCR 0xFFF // Clock control bits
|
|
|
|
/*
|
|
* Convenience routines
|
|
*/
|
|
|
|
/* Main I2C API */
|
|
|
|
/* I2C enable options */
|
|
#define I2C_FAST_MODE 0x1 // 400 khz
|
|
#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio
|
|
/* Flag 0x4 is reserved; DO NOT USE. */
|
|
#define I2C_BUS_RESET 0x8 // Perform a bus reset
|
|
void i2c_master_enable(i2c_dev *dev, uint32 flags);
|
|
|
|
#define I2C_ERROR_PROTOCOL (-1)
|
|
#define I2C_ERROR_TIMEOUT (-2)
|
|
int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
|
|
|
|
void i2c_bus_reset(const i2c_dev *dev);
|
|
|
|
/**
|
|
* @brief Disable an I2C device
|
|
*
|
|
* This function disables the corresponding peripheral and marks dev's
|
|
* state as I2C_STATE_DISABLED.
|
|
*
|
|
* @param dev Device to disable.
|
|
*/
|
|
static inline void i2c_disable(i2c_dev *dev) {
|
|
dev->regs->CR1 &= ~I2C_CR1_PE;
|
|
dev->state = I2C_STATE_DISABLED;
|
|
}
|
|
|
|
/* Start/stop conditions */
|
|
|
|
/**
|
|
* @brief Generate a start condition on the bus.
|
|
* @param dev I2C device
|
|
*/
|
|
static inline void i2c_start_condition(i2c_dev *dev) {
|
|
uint32 cr1;
|
|
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
|
|
I2C_CR1_STOP |
|
|
I2C_CR1_PEC)) {
|
|
;
|
|
}
|
|
dev->regs->CR1 |= I2C_CR1_START;
|
|
}
|
|
|
|
/**
|
|
* @brief Generate a stop condition on the bus
|
|
* @param dev I2C device
|
|
*/
|
|
static inline void i2c_stop_condition(i2c_dev *dev) {
|
|
uint32 cr1;
|
|
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
|
|
I2C_CR1_STOP |
|
|
I2C_CR1_PEC)) {
|
|
;
|
|
}
|
|
dev->regs->CR1 |= I2C_CR1_STOP;
|
|
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
|
|
I2C_CR1_STOP |
|
|
I2C_CR1_PEC)) {
|
|
;
|
|
}
|
|
|
|
}
|
|
|
|
/* IRQ enable/disable */
|
|
|
|
#ifndef _I2C_HAVE_IRQ_FIXUP
|
|
/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined,
|
|
* but we need it either way. */
|
|
#define _i2c_irq_priority_fixup(dev) ((void)0)
|
|
#endif
|
|
|
|
#define I2C_IRQ_ERROR I2C_CR2_ITERREN
|
|
#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
|
|
#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
|
|
/**
|
|
* @brief Enable one or more I2C interrupts
|
|
* @param dev I2C device
|
|
* @param irqs Bitwise or of:
|
|
* I2C_IRQ_ERROR (error interrupt),
|
|
* I2C_IRQ_EVENT (event interrupt), and
|
|
* I2C_IRQ_BUFFER (buffer interrupt).
|
|
*/
|
|
static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
|
|
_i2c_irq_priority_fixup(dev);
|
|
dev->regs->CR2 |= irqs;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable one or more I2C interrupts
|
|
* @param dev I2C device
|
|
* @param irqs Bitwise or of:
|
|
* I2C_IRQ_ERROR (error interrupt),
|
|
* I2C_IRQ_EVENT (event interrupt), and
|
|
* I2C_IRQ_BUFFER (buffer interrupt).
|
|
*/
|
|
static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
|
|
dev->regs->CR2 &= ~irqs;
|
|
}
|
|
|
|
/* ACK/NACK */
|
|
|
|
/**
|
|
* @brief Enable I2C acknowledgment
|
|
* @param dev I2C device
|
|
*/
|
|
static inline void i2c_enable_ack(i2c_dev *dev) {
|
|
dev->regs->CR1 |= I2C_CR1_ACK;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable I2C acknowledgment
|
|
* @param dev I2C device
|
|
*/
|
|
static inline void i2c_disable_ack(i2c_dev *dev) {
|
|
dev->regs->CR1 &= ~I2C_CR1_ACK;
|
|
}
|
|
|
|
/* GPIO control */
|
|
|
|
/**
|
|
* @brief Configure device GPIOs.
|
|
*
|
|
* Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
|
|
* dev->gpio_port for use with I2C device dev.
|
|
*
|
|
* @param dev I2C Device
|
|
* @see i2c_release_gpios()
|
|
*/
|
|
extern void i2c_config_gpios(const i2c_dev *dev);
|
|
|
|
/**
|
|
* @brief Release GPIOs controlling an I2C bus
|
|
*
|
|
* Releases the I2C bus controlled by dev as master, and disconnects
|
|
* GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
|
|
* dev->gpio_port from I2C device dev.
|
|
*
|
|
* @param dev I2C device
|
|
* @see i2c_config_gpios()
|
|
*/
|
|
extern void i2c_master_release_bus(const i2c_dev *dev);
|
|
|
|
/* Miscellaneous low-level routines */
|
|
|
|
void i2c_init(i2c_dev *dev);
|
|
|
|
/**
|
|
* @brief Turn on an I2C peripheral
|
|
* @param dev Device to enable
|
|
*/
|
|
static inline void i2c_peripheral_enable(i2c_dev *dev) {
|
|
dev->regs->CR1 |= I2C_CR1_PE;
|
|
}
|
|
|
|
/**
|
|
* @brief Turn off an I2C peripheral
|
|
* @param dev Device to turn off
|
|
*/
|
|
static inline void i2c_peripheral_disable(i2c_dev *dev) {
|
|
dev->regs->CR1 &= ~I2C_CR1_PE;
|
|
}
|
|
|
|
/**
|
|
* @brief Fill transmit register
|
|
* @param dev I2C device
|
|
* @param byte Byte to write
|
|
*/
|
|
static inline void i2c_write(i2c_dev *dev, uint8 byte) {
|
|
dev->regs->DR = byte;
|
|
}
|
|
|
|
/**
|
|
* @brief Set input clock frequency, in MHz
|
|
* @param dev I2C device
|
|
* @param freq Frequency, in MHz. This must be at least 2, and at most
|
|
* the APB frequency of dev's bus. (For example, if
|
|
* rcc_dev_clk(dev) == RCC_APB1, freq must be at most
|
|
* PCLK1, in MHz). There is an additional limit of 46 MHz.
|
|
*/
|
|
static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
|
|
#define I2C_MAX_FREQ_MHZ 46
|
|
ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ);
|
|
uint32 cr2 = dev->regs->CR2;
|
|
cr2 &= ~I2C_CR2_FREQ;
|
|
cr2 |= freq;
|
|
dev->regs->CR2 = freq;
|
|
#undef I2C_MAX_FREQ_MHZ
|
|
}
|
|
|
|
/**
|
|
* @brief Set I2C clock control register.
|
|
*
|
|
* See the chip reference manual for the details.
|
|
*
|
|
* @param dev I2C device
|
|
* @param val Value to use for clock control register (in
|
|
* Fast/Standard mode)
|
|
*/
|
|
static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
|
|
uint32 ccr = dev->regs->CCR;
|
|
ccr &= ~I2C_CCR_CCR;
|
|
ccr |= val;
|
|
dev->regs->CCR = ccr;
|
|
}
|
|
|
|
/**
|
|
* @brief Set SCL rise time
|
|
* @param dev I2C device
|
|
* @param trise Maximum rise time in fast/standard mode (see chip
|
|
* reference manual for the relevant formulas).
|
|
*/
|
|
static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
|
|
dev->regs->TRISE = trise;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|