Add software-I2C (#2514)

This commit is contained in:
Tom van Dijk
2020-04-03 11:06:15 +02:00
committed by GitHub
parent e01e8fcf35
commit fba667b75c
16 changed files with 882 additions and 21 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ COMMON_DEMO_SRCS += $(SRC_ARCH)/led_hw.c
COMMON_DEMO_SRCS += $(SRC_ARCH)/mcu_periph/gpio_arch.c
endif
COMMON_DEMO_SRCS += mcu_periph/i2c.c $(SRC_ARCH)/mcu_periph/i2c_arch.c
COMMON_DEMO_SRCS += mcu_periph/i2c.c mcu_periph/softi2c.c $(SRC_ARCH)/mcu_periph/i2c_arch.c
COMMON_DEMO_SRCS += mcu_periph/uart.c
COMMON_DEMO_SRCS += $(SRC_ARCH)/mcu_periph/uart_arch.c
ifeq ($(ARCH), linux)
+1
View File
@@ -136,6 +136,7 @@ endif # TARGET == fbw
ifneq ($(TARGET), fbw)
$(TARGET).srcs += mcu_periph/i2c.c
$(TARGET).srcs += mcu_periph/softi2c.c
$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c
endif
+1
View File
@@ -120,6 +120,7 @@ endif
##
$(TARGET).srcs += mcu_periph/i2c.c
$(TARGET).srcs += mcu_periph/softi2c.c
$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c
include $(CFG_SHARED)/uart.makefile
@@ -91,6 +91,7 @@ endif
#
ifneq ($(TARGET),fbw)
$(TARGET).srcs += mcu_periph/i2c.c
$(TARGET).srcs += mcu_periph/softi2c.c
$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c
endif
+1
View File
@@ -12,6 +12,7 @@
</header>
<makefile>
<file name="i2c.c" dir="mcu_periph"/>
<file name="softi2c.c" dir="mcu_periph"/>
<file_arch name="i2c_arch.c" dir="mcu_periph"/>
</makefile>
</module>
+25 -3
View File
@@ -46,6 +46,12 @@
#define I2C_THREAD_STACK_SIZE 512
#endif
static bool i2c_chibios_idle(struct i2c_periph *p) __attribute__((unused));
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
static void i2c_chibios_setbitrate(struct i2c_periph *p, int bitrate) __attribute__((unused));
#if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
// private I2C init structure
@@ -209,6 +215,10 @@ static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
*/
void i2c1_hw_init(void)
{
i2c1.idle = i2c_chibios_idle;
i2c1.submit = i2c_chibios_submit;
i2c1.setbitrate = i2c_chibios_setbitrate;
i2cStart(&I2CD1, &i2cfg1);
i2c1.reg_addr = &I2CD1;
i2c1.errors = &i2c1_errors;
@@ -263,6 +273,10 @@ static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
*/
void i2c2_hw_init(void)
{
i2c2.idle = i2c_chibios_idle;
i2c2.submit = i2c_chibios_submit;
i2c2.setbitrate = i2c_chibios_setbitrate;
i2cStart(&I2CD2, &i2cfg2);
i2c2.reg_addr = &I2CD2;
i2c2.errors = &i2c2_errors;
@@ -317,6 +331,10 @@ static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
*/
void i2c3_hw_init(void)
{
i2c3.idle = i2c_chibios_idle;
i2c3.submit = i2c_chibios_submit;
i2c3.setbitrate = i2c_chibios_setbitrate;
i2cStart(&I2CD3, &i2cfg3);
i2c3.reg_addr = &I2CD3;
i2c3.init_struct = NULL;
@@ -372,6 +390,10 @@ static THD_WORKING_AREA(wa_thd_i2c4, 128);
*/
void i2c4_hw_init(void)
{
i2c4.idle = i2c_chibios_idle;
i2c4.submit = i2c_chibios_submit;
i2c4.setbitrate = i2c_chibios_setbitrate;
i2cStart(&I2CD4, &i2cfg4);
i2c4.reg_addr = &I2CD4;
i2c4.init_struct = NULL;
@@ -411,7 +433,7 @@ void i2c_event(void) {}
* Empty, for paparazzi compatibility only. Bitrate is already
* set in i2cX_hw_init()
*/
void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
/**
* i2c_submit() function
@@ -430,7 +452,7 @@ void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __
* @param[in] p pointer to a @p i2c_periph struct
* @param[in] t pointer to a @p i2c_transaction struct
*/
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
{
#if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
// sys lock
@@ -469,7 +491,7 @@ bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
*
* Empty, for paparazzi compatibility only
*/
bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
static bool i2c_chibios_idle(struct i2c_periph *p __attribute__((unused)))
{
return FALSE;
}
+25 -3
View File
@@ -42,6 +42,12 @@
#define I2C_THREAD_PRIO 10
#endif
static bool i2c_linux_idle(struct i2c_periph *p __attribute__((unused))) __attribute__((unused));
static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
static void i2c_linux_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) __attribute__((unused));
static void *i2c_thread(void *thread_data);
// private I2C init structure
@@ -66,16 +72,16 @@ void i2c_event(void)
{
}
void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused)))
static void i2c_linux_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused)))
{
}
bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
static bool i2c_linux_idle(struct i2c_periph *p __attribute__((unused)))
{
return true;
}
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t)
{
// get mutex lock and condition
pthread_mutex_t *mutex = &(((struct i2c_thread_t *)(p->init_struct))->mutex);
@@ -204,6 +210,10 @@ struct i2c_thread_t i2c0_thread;
void i2c0_hw_init(void)
{
i2c0.idle = i2c_linux_idle;
i2c0.submit = i2c_linux_submit;
i2c0.setbitrate = i2c_linux_setbitrate;
i2c0.reg_addr = (void *)open("/dev/i2c-0", O_RDWR);
i2c0.errors = &i2c0_errors;
@@ -224,6 +234,10 @@ struct i2c_thread_t i2c1_thread;
void i2c1_hw_init(void)
{
i2c1.idle = i2c_linux_idle;
i2c1.submit = i2c_linux_submit;
i2c1.setbitrate = i2c_linux_setbitrate;
i2c1.reg_addr = (void *)open("/dev/i2c-1", O_RDWR);
i2c1.errors = &i2c1_errors;
@@ -244,6 +258,10 @@ struct i2c_thread_t i2c2_thread;
void i2c2_hw_init(void)
{
i2c2.idle = i2c_linux_idle;
i2c2.submit = i2c_linux_submit;
i2c2.setbitrate = i2c_linux_setbitrate;
i2c2.reg_addr = (void *)open("/dev/i2c-2", O_RDWR);
i2c2.errors = &i2c2_errors;
@@ -264,6 +282,10 @@ struct i2c_thread_t i2c3_thread;
void i2c3_hw_init(void)
{
i2c3.idle = i2c_linux_idle;
i2c3.submit = i2c_linux_submit;
i2c3.setbitrate = i2c_linux_setbitrate;
i2c3.reg_addr = (void *)open("/dev/i2c-3", O_RDWR);
i2c3.errors = &i2c3_errors;
+15 -3
View File
@@ -33,6 +33,12 @@
#include BOARD_CONFIG
#include "armVIC.h"
static bool i2c_lpc21_idle(struct i2c_periph *p) __attribute__((unused));
static bool i2c_lpc21_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
static void i2c_lpc21_setbitrate(struct i2c_periph *p, int bitrate) __attribute__((unused));
///////////////////
// I2C Automaton //
///////////////////
@@ -231,6 +237,9 @@ uint8_t i2c0_vic_channel;
/* SCL0 on P0.2 */
void i2c0_hw_init(void)
{
i2c0.idle = i2c_lpc21_idle;
i2c0.submit = i2c_lpc21_submit;
i2c0.setbitrate = i2c_lpc21_setbitrate;
i2c0.reg_addr = I2C0;
i2c0_vic_channel = VIC_I2C0;
@@ -316,6 +325,9 @@ uint8_t i2c1_vic_channel;
/* SCL1 on P0.11 */
void i2c1_hw_init(void)
{
i2c1.idle = i2c_lpc21_idle;
i2c1.submit = i2c_lpc21_submit;
i2c1.setbitrate = i2c_lpc21_setbitrate;
i2c1.reg_addr = I2C1;
i2c1_vic_channel = VIC_I2C1;
@@ -341,12 +353,12 @@ void i2c1_hw_init(void)
#endif /* USE_I2C1 */
bool i2c_idle(struct i2c_periph *p)
static bool i2c_lpc21_idle(struct i2c_periph *p)
{
return p->status == I2CIdle;
}
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
static bool i2c_lpc21_submit(struct i2c_periph *p, struct i2c_transaction *t)
{
uint8_t idx;
@@ -383,7 +395,7 @@ bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
void i2c_event(void) { }
void i2c_setbitrate(struct i2c_periph *p, int bitrate)
static void i2c_lpc21_setbitrate(struct i2c_periph *p, int bitrate)
{
int period = 15000000 / 2 / bitrate;
// Max 400kpbs
@@ -77,5 +77,6 @@ static inline void gpio_setup_input(uint32_t port __attribute__((unused)), uint1
static inline void gpio_set(uint32_t port __attribute__((unused)), uint16_t pin __attribute__((unused))) {}
static inline void gpio_clear(uint32_t port __attribute__((unused)), uint16_t pin __attribute__((unused))) {}
static inline void gpio_toggle(uint32_t port __attribute__((unused)), uint16_t pin __attribute__((unused))) {}
static inline uint16_t gpio_get(uint32_t gpioport __attribute__((unused)), uint16_t gpios __attribute__((unused))) { return FALSE; }
#endif /* GPIO_ARCH_H */
+12 -3
View File
@@ -27,16 +27,19 @@
#include "mcu_periph/i2c.h"
bool i2c_idle(struct i2c_periph *p __attribute__((unused))) { return true; }
bool i2c_submit(struct i2c_periph *p __attribute__((unused)), struct i2c_transaction *t __attribute__((unused))) { return true;}
static bool __attribute__((unused)) i2c_sim_idle(struct i2c_periph *p __attribute__((unused))) { return true; }
static bool __attribute__((unused)) i2c_sim_submit(struct i2c_periph *p __attribute__((unused)), struct i2c_transaction *t __attribute__((unused))) { return true;}
static void __attribute__((unused)) i2c_sim_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) { }
void i2c_event(void) { }
void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) { }
#if USE_I2C0
struct i2c_errors i2c0_errors;
void i2c0_hw_init(void)
{
i2c0.idle = i2c_sim_idle;
i2c0.submit = i2c_sim_submit;
i2c0.setbitrate = i2c_sim_setbitrate;
i2c0.errors = &i2c0_errors;
ZEROS_ERR_COUNTER(i2c0_errors);
}
@@ -48,6 +51,9 @@ struct i2c_errors i2c1_errors;
void i2c1_hw_init(void)
{
i2c1.idle = i2c_sim_idle;
i2c1.submit = i2c_sim_submit;
i2c1.setbitrate = i2c_sim_setbitrate;
i2c1.errors = &i2c1_errors;
ZEROS_ERR_COUNTER(i2c1_errors);
}
@@ -59,6 +65,9 @@ struct i2c_errors i2c2_errors;
void i2c2_hw_init(void)
{
i2c2.idle = i2c_sim_idle;
i2c2.submit = i2c_sim_submit;
i2c2.setbitrate = i2c_sim_setbitrate;
i2c2.errors = &i2c2_errors;
ZEROS_ERR_COUNTER(i2c2_errors);
}
+17 -3
View File
@@ -38,6 +38,11 @@
#include "mcu_periph/gpio.h"
static bool i2c_stm32_idle(struct i2c_periph *periph) __attribute__((unused));
static bool i2c_stm32_submit(struct i2c_periph *periph, struct i2c_transaction *t) __attribute__((unused));
static void i2c_stm32_setbitrate(struct i2c_periph *periph, int bitrate) __attribute__((unused));
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
@@ -845,6 +850,9 @@ struct i2c_errors i2c1_errors;
void i2c1_hw_init(void)
{
i2c1.idle = i2c_stm32_idle;
i2c1.submit = i2c_stm32_submit;
i2c1.setbitrate = i2c_stm32_setbitrate;
i2c1.reg_addr = (void *)I2C1;
i2c1.init_struct = NULL;
@@ -916,6 +924,9 @@ struct i2c_errors i2c2_errors;
void i2c2_hw_init(void)
{
i2c2.idle = i2c_stm32_idle;
i2c2.submit = i2c_stm32_submit;
i2c2.setbitrate = i2c_stm32_setbitrate;
i2c2.reg_addr = (void *)I2C2;
i2c2.init_struct = NULL;
@@ -989,6 +1000,9 @@ struct i2c_errors i2c3_errors;
void i2c3_hw_init(void)
{
i2c3.idle = i2c_stm32_idle;
i2c3.submit = i2c_stm32_submit;
i2c3.setbitrate = i2c_stm32_setbitrate;
i2c3.reg_addr = (void *)I2C3;
i2c3.init_struct = NULL;
@@ -1054,7 +1068,7 @@ void i2c3_er_isr(void)
// -short wires, low capacitance bus: IMU: high speed
// -long wires with a lot of capacitance: motor controller: put speed as low as possible
void i2c_setbitrate(struct i2c_periph *periph, int bitrate)
static void i2c_stm32_setbitrate(struct i2c_periph *periph, int bitrate)
{
// If NOT Busy
if (i2c_idle(periph)) {
@@ -1312,7 +1326,7 @@ void i2c_event(void)
/////////////////////////////////////////////////////////
// Implement Interface Functions
bool i2c_submit(struct i2c_periph *periph, struct i2c_transaction *t)
static bool i2c_stm32_submit(struct i2c_periph *periph, struct i2c_transaction *t)
{
if (periph->watchdog > WD_DELAY) {
return false;
@@ -1349,7 +1363,7 @@ bool i2c_submit(struct i2c_periph *periph, struct i2c_transaction *t)
return true;
}
bool i2c_idle(struct i2c_periph *periph)
static bool i2c_stm32_idle(struct i2c_periph *periph)
{
// This is actually a difficult function:
// -simply reading the status flags can clear bits and corrupt the transaction
+14 -1
View File
@@ -43,10 +43,14 @@
#define USING_UART 1
#include "mcu_periph/uart.h"
#endif
#if USE_I2C0 || USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
#if USE_I2C0 || USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 || USE_SOFTI2C0 || USE_SOFTI2C1
#define USING_I2C 1
#include "mcu_periph/i2c.h"
#endif
#if USE_SOFTI2C0 || USE_SOFTI2C1
#define USING_SOFTI2C 1
#include "mcu_periph/softi2c.h"
#endif
#if USE_ADC
#include "mcu_periph/adc.h"
#endif
@@ -176,6 +180,12 @@ void mcu_init(void)
#ifdef USE_I2C4
i2c4_init();
#endif
#ifdef USE_SOFTI2C0
softi2c0_init();
#endif
#ifdef USE_SOFTI2C1
softi2c1_init();
#endif
#if USE_ADC
adc_init();
#endif
@@ -250,6 +260,9 @@ void mcu_event(void)
#if USING_I2C
i2c_event();
#endif
#if USING_SOFTI2C
softi2c_event();
#endif
#if USE_USB_SERIAL
VCOM_event();
+20 -1
View File
@@ -249,6 +249,14 @@ static void send_i2c4_err(struct transport_tx *trans, struct link_device *dev)
#endif /* USE_I2C4 */
#if USE_SOFTI2C0
extern void send_softi2c0_err(struct transport_tx *trans, struct link_device *dev);
#endif /* USE_SOFTI2C0 */
#if USE_SOFTI2C1
extern void send_softi2c1_err(struct transport_tx *trans, struct link_device *dev);
#endif /* USE_SOFTI2C1 */
#if PERIODIC_TELEMETRY
static void send_i2c_err(struct transport_tx *trans __attribute__((unused)),
struct link_device *dev __attribute__((unused)))
@@ -278,13 +286,21 @@ static void send_i2c_err(struct transport_tx *trans __attribute__((unused)),
case 4:
#if USE_I2C4
send_i2c4_err(trans, dev);
#endif
case 5:
#if USE_SOFTI2C0
send_softi2c0_err(trans, dev);
#endif
case 6:
#if USE_SOFTI2C1
send_softi2c1_err(trans, dev);
#endif
break;
default:
break;
}
_i2c_nb_cnt++;
if (_i2c_nb_cnt == 5) {
if (_i2c_nb_cnt == 7) {
_i2c_nb_cnt = 0;
}
}
@@ -354,6 +370,7 @@ bool i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
// Wait for transaction to complete
float start_t = get_sys_time_float();
while (t->status == I2CTransPending || t->status == I2CTransRunning) {
if (p->spin) p->spin(p);
if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
break; // timeout after 1 second
}
@@ -375,6 +392,7 @@ bool i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
// Wait for transaction to complete
float start_t = get_sys_time_float();
while (t->status == I2CTransPending || t->status == I2CTransRunning) {
if (p->spin) p->spin(p);
if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
break; // timeout after 1 second
}
@@ -396,6 +414,7 @@ bool i2c_blocking_transceive(struct i2c_periph *p, struct i2c_transaction *t,
// Wait for transaction to complete
float start_t = get_sys_time_float();
while (t->status == I2CTransPending || t->status == I2CTransRunning) {
if (p->spin) p->spin(p);
if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
break; // timeout after 1 second
}
+33 -3
View File
@@ -135,7 +135,18 @@ struct i2c_transaction {
/** I2C peripheral structure.
*/
struct i2c_periph;
typedef bool i2c_idle_fn_t(struct i2c_periph *p);
typedef bool i2c_submit_fn_t(struct i2c_periph *p, struct i2c_transaction *t);
typedef void i2c_setbitrate_fn_t(struct i2c_periph *p, int bitrate);
typedef void i2c_spin_fn_t(struct i2c_periph *p); // To update peripherals within tight loops, e.g. the blocking functions. Leave NULL if not required.
struct i2c_periph {
/* architecture-specific functions */
i2c_idle_fn_t *idle;
i2c_submit_fn_t *submit;
i2c_setbitrate_fn_t *setbitrate;
i2c_spin_fn_t *spin;
/* circular buffer holding transactions */
struct i2c_transaction *trans[I2C_TRANSACTION_QUEUE_LEN];
uint8_t trans_insert_idx;
@@ -223,6 +234,18 @@ extern void i2c4_init(void);
#endif /* USE_I2C4 */
#if USE_SOFTI2C0
extern struct i2c_periph softi2c0;
extern void softi2c0_init(void);
#endif /* USE_SOFTI2C0 */
#if USE_SOFTI2C1
extern struct i2c_periph softi2c1;
extern void softi2c1_init(void);
#endif /* USE_SOFTI2C1 */
/** Initialize I2C peripheral */
extern void i2c_init(struct i2c_periph *p);
@@ -230,7 +253,9 @@ extern void i2c_init(struct i2c_periph *p);
* @param p i2c peripheral to be used
* @return TRUE if idle
*/
extern bool i2c_idle(struct i2c_periph *p);
static inline bool i2c_idle(struct i2c_periph *p) {
return p->idle(p);
}
/** Submit a I2C transaction.
* Must be implemented by the underlying architecture
@@ -238,13 +263,18 @@ extern bool i2c_idle(struct i2c_periph *p);
* @param t i2c transaction
* @return TRUE if insertion to the transaction queue succeeded
*/
extern bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t);
static inline bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t) {
return p->submit(p, t);
}
/** Set I2C bitrate.
* @param p i2c peripheral to be used
* @param bitrate bitrate
*/
extern void i2c_setbitrate(struct i2c_periph *p, int bitrate);
static inline void i2c_setbitrate(struct i2c_periph *p, int bitrate) {
p->setbitrate(p, bitrate);
}
extern void i2c_event(void);
/*
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2020 Tom van Dijk <tomvand@users.noreply.github.com>
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
/**
* @file mcu_periph/softi2c.h
* Platform-independent software I2C implementation.
* Can be used transparently in place of the hardware I2C in i2c.h.
*/
#ifndef MCU_PERIPH_SOFTI2C_H
#define MCU_PERIPH_SOFTI2C_H
#include "mcu_periph/i2c.h"
void softi2c_event(void);
#if USE_SOFTI2C0
extern void softi2c0_hw_init(void);
#endif /* USE_SOFTI2C0 */
#if USE_SOFTI2C1
extern void softi2c1_hw_init(void);
#endif /* USE_SOFTI2C1 */
#endif // MCU_PERIPH_SOFTI2C_H