From 937c954d925690476df11760dedf3e0b4361ecf9 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 11 Dec 2019 22:55:52 +0100 Subject: [PATCH 1/4] cpu/lpc2387: implement periph/i2c The lpc23xx MCU has up to three I2C interfaces. This adds a driver for it. The peripheral works in interrupt mode, each change of the state machine will generate an interrupt. The response to the states are laid out in the data sheet. This replaces the old driver that was removed in c560e28eb69000b9c68b4b6210aae271a9d8b622 --- cpu/lpc2387/include/periph_cpu.h | 33 ++ cpu/lpc2387/include/vendor/lpc23xx.h | 29 ++ cpu/lpc2387/periph/i2c.c | 484 +++++++++++++++++++++++++++ 3 files changed, 546 insertions(+) create mode 100644 cpu/lpc2387/periph/i2c.c diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h index c0d6fa058f7f..7d48a143e8b5 100644 --- a/cpu/lpc2387/include/periph_cpu.h +++ b/cpu/lpc2387/include/periph_cpu.h @@ -195,7 +195,40 @@ typedef struct { uint32_t pinsel_msk; /**< PINSEL Mask for ADC pin */ } adc_conf_t; +/** + * @brief Override I2C clock speed values + * @{ + */ +#define HAVE_I2C_SPEED_T +typedef enum { + I2C_SPEED_LOW = 10000, /**< low speed mode: ~10 kbit/s */ + I2C_SPEED_NORMAL = 100000, /**< normal mode: ~100 kbit/s */ + I2C_SPEED_FAST = 400000, /**< fast mode: ~400 kbit/s */ +} i2c_speed_t; /* @} */ + +/** + * @brief I2C device configuration + */ +typedef struct { + lpc23xx_i2c_t *dev; /**< pointer to the I2C device */ + i2c_speed_t speed; /**< I2C bus speed */ + uint8_t irq_prio; /**< priority of the I2C IRQ */ + uint8_t pinsel_sda; /**< PINSEL# of the SDA pin */ + uint8_t pinsel_scl; /**< PINSEL# of the SCL pin */ + uint32_t pinsel_msk_sda;/**< SDA PINSEL Mask */ + uint32_t pinsel_msk_scl;/**< SCL PINSEL Mask */ +} i2c_conf_t; +/* @} */ + +/** + * @name Use shared I2C functions + * @{ + */ +#define PERIPH_I2C_NEED_READ_REG +#define PERIPH_I2C_NEED_WRITE_REG +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/lpc2387/include/vendor/lpc23xx.h b/cpu/lpc2387/include/vendor/lpc23xx.h index 60dc70e1f63f..0189bf3d145f 100644 --- a/cpu/lpc2387/include/vendor/lpc23xx.h +++ b/cpu/lpc2387/include/vendor/lpc23xx.h @@ -771,8 +771,35 @@ typedef struct { #define U3FDR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x28)) #define U3TER (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x30)) +/** + * @brief Generic I2C register map + */ +typedef struct { + REG32 CONSET; /**< Control Set Register */ + REG32 STAT; /**< Status Register */ + REG32 DAT; /**< Data Register */ + REG32 ADR; /**< Slave Address Register */ + REG32 SCLH; /**< Duty Cycle High Half Word */ + REG32 SCLL; /**< Duty Cycle Low Half Word */ + REG32 CONCLR; /**< Control Clear Register */ +} lpc23xx_i2c_t; + +/* I2C Control Set Register */ +#define I2CONSET_AA 0x00000004 /**< Assert acknowledge */ +#define I2CONSET_SI 0x00000008 /**< Interrupt flag */ +#define I2CONSET_STO 0x00000010 /**< STOP flag */ +#define I2CONSET_STA 0x00000020 /**< START flag */ +#define I2CONSET_I2EN 0x00000040 /**< Interface enable */ + +/* I2C Control clear Register */ +#define I2CONCLR_AAC 0x00000004 /**< clear Assert ACK */ +#define I2CONCLR_SIC 0x00000008 /**< clear Interrupt */ +#define I2CONCLR_STAC 0x00000020 /**< clear START flag */ +#define I2CONCLR_I2ENC 0x00000040 /**< Interface disable */ + /* I2C Interface 0 */ #define I2C0_BASE_ADDR 0xE001C000 +#define I2C0 ((lpc23xx_i2c_t *)I2C0_BASE_ADDR) #define I20CONSET (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x00)) #define I20STAT (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x04)) #define I20DAT (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x08)) @@ -783,6 +810,7 @@ typedef struct { /* I2C Interface 1 */ #define I2C1_BASE_ADDR 0xE005C000 +#define I2C1 ((lpc23xx_i2c_t *)I2C1_BASE_ADDR) #define I21CONSET (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x00)) #define I21STAT (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x04)) #define I21DAT (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x08)) @@ -793,6 +821,7 @@ typedef struct { /* I2C Interface 2 */ #define I2C2_BASE_ADDR 0xE0080000 +#define I2C2 ((lpc23xx_i2c_t *)I2C2_BASE_ADDR) #define I22CONSET (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x00)) #define I22STAT (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x04)) #define I22DAT (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x08)) diff --git a/cpu/lpc2387/periph/i2c.c b/cpu/lpc2387/periph/i2c.c new file mode 100644 index 000000000000..fa61ffbe8b8a --- /dev/null +++ b/cpu/lpc2387/periph/i2c.c @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2020 Beuth Hochschule für Technik Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_lpc2387 + * @ingroup drivers_periph_i2c + * @{ + * + * @file + * @brief Low-level I2C driver implementation for lpc23xx + * + * @author Benjamin Valentin + * + * @} + */ + +#include +#include +#include + +#include "cpu.h" +#include "board.h" +#include "byteorder.h" +#include "periph_conf.h" +#include "periph/i2c.h" + +#include "sched.h" +#include "thread.h" +#include "mutex.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if I2C_NUMOF > 0 +static void I2C0_IRQHandler(void) __attribute__((interrupt("IRQ"))); +#endif +#if I2C_NUMOF > 1 +static void I2C1_IRQHandler(void) __attribute__((interrupt("IRQ"))); +#endif +#if I2C_NUMOF > 2 +static void I2C2_IRQHandler(void) __attribute__((interrupt("IRQ"))); +#endif + +/** + * We only ever need two buffers for read/write reg + */ +#define TRX_BUFS_MAX (2) +static struct i2c_ctx { + mutex_t lock; + mutex_t tx_done; + uint8_t *buf[TRX_BUFS_MAX]; + uint8_t *buf_end[TRX_BUFS_MAX]; + uint8_t *cur; + uint8_t *end; + int res; + uint8_t addr[TRX_BUFS_MAX]; + uint8_t buf_num; + uint8_t buf_cur; +} ctx[I2C_NUMOF] = { +#if I2C_NUMOF > 0 + { .lock = MUTEX_INIT, .tx_done = MUTEX_INIT_LOCKED }, +#endif +#if I2C_NUMOF > 1 + { .lock = MUTEX_INIT, .tx_done = MUTEX_INIT_LOCKED }, +#endif +#if I2C_NUMOF > 2 + { .lock = MUTEX_INIT, .tx_done = MUTEX_INIT_LOCKED }, +#endif +}; + +static void poweron(lpc23xx_i2c_t *i2c) +{ + switch ((uint32_t)i2c) { + case I2C0_BASE_ADDR: + PCONP |= PCI2C0; + break; + case I2C1_BASE_ADDR: + PCONP |= PCI2C1; + break; + case I2C2_BASE_ADDR: + PCONP |= PCI2C2; + break; + } +} + +static void poweroff(lpc23xx_i2c_t *i2c) +{ + switch ((uint32_t)i2c) { + case I2C0_BASE_ADDR: + PCONP &= ~PCI2C0; + break; + case I2C1_BASE_ADDR: + PCONP &= ~PCI2C1; + break; + case I2C2_BASE_ADDR: + PCONP &= ~PCI2C2; + break; + } +} + +int i2c_acquire(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + mutex_lock(&ctx[dev].lock); + poweron(i2c_config[dev].dev); + + return 0; +} + +void i2c_release(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + poweroff(i2c_config[dev].dev); + mutex_unlock(&ctx[dev].lock); +} + +static void _set_baud(lpc23xx_i2c_t *i2c, uint32_t baud) +{ + uint32_t pclksel, prescale; + lpc2387_pclk_scale(CLOCK_CORECLOCK, baud, &pclksel, &prescale); + + switch ((uint32_t)i2c) { + case I2C0_BASE_ADDR: + PCLKSEL0 &= ~(BIT14 | BIT15); + PCLKSEL0 |= pclksel << 14; + I20SCLL = prescale / 2; + I20SCLH = prescale / 2; + break; + case I2C1_BASE_ADDR: + PCLKSEL1 &= ~(BIT6 | BIT7); + PCLKSEL1 |= pclksel << 6; + I21SCLL = prescale / 2; + I21SCLH = prescale / 2; + break; + case I2C2_BASE_ADDR: + PCLKSEL1 &= ~(BIT20 | BIT21); + PCLKSEL1 |= pclksel << 20; + I22SCLL = prescale / 2; + I22SCLH = prescale / 2; + break; + } +} + +static unsigned _get_irq(i2c_t dev) +{ + switch ((uint32_t)i2c_config[dev].dev) { + case I2C0_BASE_ADDR: + return I2C0_INT; + case I2C1_BASE_ADDR: + return I2C1_INT; + case I2C2_BASE_ADDR: + return I2C2_INT; + } + + return 0; +} + +static void _install_irq(i2c_t dev) +{ + switch (dev) { +#if I2C_NUMOF > 0 + case 0: + install_irq(_get_irq(dev), I2C0_IRQHandler, i2c_config[dev].irq_prio); + break; +#endif +#if I2C_NUMOF > 1 + case 1: + install_irq(_get_irq(dev), I2C1_IRQHandler, i2c_config[dev].irq_prio); + break; +#endif +#if I2C_NUMOF > 2 + case 2: + install_irq(_get_irq(dev), I2C2_IRQHandler, i2c_config[dev].irq_prio); + break; +#endif + } +} + +void i2c_init(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + const i2c_conf_t *cfg = &i2c_config[dev]; + lpc23xx_i2c_t *i2c = cfg->dev; + + poweron(i2c); + + /* configure SDA & SCL pins */ + *(&PINSEL0 + cfg->pinsel_sda) |= cfg->pinsel_msk_sda; + *(&PINSEL0 + cfg->pinsel_scl) |= cfg->pinsel_msk_scl; + + /* clear control register */ + i2c->CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC + | I2CONCLR_I2ENC; + + _set_baud(i2c, cfg->speed); + + _install_irq(dev); + + /* enable the interface */ + i2c->CONSET = I2CONSET_I2EN; + + poweroff(i2c); +} + +static void _end_tx(i2c_t dev, unsigned res) +{ + ctx[dev].res = res; + mutex_unlock(&ctx[dev].tx_done); +} + +static void _next_buffer(i2c_t dev) +{ + /* We only need two buffers max. + This can only be called for the first buffer + as there is no next buffer for the second buffer */ + assert(ctx[dev].buf_cur == 0); + + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + /* if mode (read/write) changed, send START again */ + if (ctx[dev].addr[0] != ctx[dev].addr[1]) { + i2c->CONSET = I2CONSET_STA; + } + + ctx[dev].cur = ctx[dev].buf[1]; + ctx[dev].end = ctx[dev].buf_end[1]; + ctx[dev].buf_cur = 1; +} + +static void irq_handler(i2c_t dev) +{ + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + unsigned stat = i2c->STAT; + + DEBUG("[i2c] STAT: %x\n", stat); + + switch (stat) { + case 0x00: /* Bus Error */ + DEBUG("[i2c] Bus Error\n"); + _end_tx(dev, -EIO); + break; + + case 0x08: /* A Start Condition is issued. */ + case 0x10: /* A repeated Start Condition is issued */ + ctx[dev].cur = ctx[dev].buf[ctx[dev].buf_cur]; + i2c->DAT = ctx[dev].addr[ctx[dev].buf_cur]; + i2c->CONSET = I2CONSET_AA; + i2c->CONCLR = I2CONCLR_STAC; + break; + + case 0x20: /* Address NACK (write) */ + case 0x48: /* Address NACK (read) */ + /* slave did not ACK address - send STOP */ + i2c->CONSET = I2CONSET_STO | I2CONSET_AA; + _end_tx(dev, -ENXIO); + break; + + case 0x18: /* Master Transmit, SLA_R has been sent */ + i2c->DAT = *ctx[dev].cur++; + i2c->CONSET = I2CONSET_AA; + break; + + case 0x28: /* Data byte has been transmitted */ + + if (ctx[dev].cur == ctx[dev].end) { + /* we transmitted all buffers */ + if (ctx[dev].buf_cur == ctx[dev].buf_num) { + i2c->CONSET = I2CONSET_STO | I2CONSET_AA; + _end_tx(dev, 0); + break; + } else { + _next_buffer(dev); + } + } + + i2c->DAT = *ctx[dev].cur++; + i2c->CONSET = I2CONSET_AA; + break; + + case 0x30: /* Data NACK */ + i2c->CONSET = I2CONSET_STO | I2CONSET_AA; + _end_tx(dev, 0); + break; + + case 0x38: /* Arbitration has been lost */ + i2c->CONSET = I2CONSET_STA | I2CONSET_AA; + break; + + case 0x40: /* Master Receive, SLA_R has been sent */ + + /* if we only want to read one byte, send NACK already */ + if (ctx[dev].cur + 1 == ctx[dev].end) { + i2c->CONCLR = I2CONCLR_AAC; + } else { + i2c->CONSET = I2CONSET_AA; + } + break; + + case 0x50: /* Data byte has been received */ + + *ctx[dev].cur++ = i2c->DAT; + + if (ctx[dev].cur == ctx[dev].end) { + i2c->CONCLR = I2CONCLR_AAC; + } else { + i2c->CONSET = I2CONSET_AA; + } + + break; + + case 0x58: /* Data received, NACK */ + *ctx[dev].cur = i2c->DAT; + + if (ctx[dev].buf_cur != ctx[dev].buf_num) { + i2c->CONSET = I2CONSET_AA; + _next_buffer(dev); + } else { + i2c->CONSET = I2CONSET_AA | I2CONSET_STO; + _end_tx(dev, 0); + } + break; + + } + + /* clear interrupt flag */ + i2c->CONCLR = I2CONCLR_SIC; +} + +static void _init_buffer(i2c_t dev, uint8_t idx, uint8_t addr, + uint8_t *data, size_t len) +{ + ctx[dev].addr[idx] = addr; + ctx[dev].buf[idx] = data; + ctx[dev].buf_end[idx] = data + len; + + ctx[dev].buf_num = idx; + + ctx[dev].buf_cur = 0; + ctx[dev].cur = ctx[dev].buf[0]; + ctx[dev].end = ctx[dev].buf_end[0]; +} + +int i2c_read_bytes(i2c_t dev, uint16_t addr, + void *data, size_t len, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + /* TODO: 10 bit addresses */ + if (flags) { + return -ENOTSUP; + } + + _init_buffer(dev, 0, 1 | (addr << 1), (void*)data, len); + + /* set Start flag */ + i2c->CONSET = I2CONSET_STA; + + mutex_lock(&ctx[dev].tx_done); + return ctx[dev].res; +} + +int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, + uint8_t flags) +{ + assert(dev < I2C_NUMOF); + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + /* TODO: 10 bit addresses */ + if (flags) { + return -ENOTSUP; + } + + _init_buffer(dev, 0, addr << 1, (void*)data, len); + + /* set Start flag */ + i2c->CONSET = I2CONSET_STA; + + mutex_lock(&ctx[dev].tx_done); + return ctx[dev].res; +} + +int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg, + void *data, size_t len, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + /* TODO: 10 bit addresses */ + if (flags & ~I2C_REG16) { + return -ENOTSUP; + } + + /* Handle endianness of register if 16 bit */ + if (flags & I2C_REG16) { + reg = htons(reg); /* Make sure register is in big-endian on I2C bus */ + } + + _init_buffer(dev, 0, addr << 1, (void*)®, (flags & I2C_REG16) ? 2 : 1); + _init_buffer(dev, 1, 1 | (addr << 1), (void*)data, len); + + /* set Start flag */ + i2c->CONSET = I2CONSET_STA; + + mutex_lock(&ctx[dev].tx_done); + return ctx[dev].res; +} + +int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg, + const void *data, size_t len, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + lpc23xx_i2c_t *i2c = i2c_config[dev].dev; + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + /* TODO: 10 bit addresses */ + if (flags & ~I2C_REG16) { + return -ENOTSUP; + } + + /* Handle endianness of register if 16 bit */ + if (flags & I2C_REG16) { + reg = htons(reg); /* Make sure register is in big-endian on I2C bus */ + } + + _init_buffer(dev, 0, addr << 1, (void*)®, (flags & I2C_REG16) ? 2 : 1); + _init_buffer(dev, 1, addr << 1, (void*)data, len); + + /* set Start flag */ + i2c->CONSET = I2CONSET_STA; + + mutex_lock(&ctx[dev].tx_done); + return ctx[dev].res; +} + +#if I2C_NUMOF > 0 +static void I2C0_IRQHandler(void) +{ + irq_handler(0); + VICVectAddr = 0; /* Acknowledge Interrupt */ +} +#endif +#if I2C_NUMOF > 1 +static void I2C1_IRQHandler(void) +{ + irq_handler(1); + VICVectAddr = 0; /* Acknowledge Interrupt */ +} +#endif +#if I2C_NUMOF > 2 +static void I2C2_IRQHandler(void) +{ + irq_handler(2); + VICVectAddr = 0; /* Acknowledge Interrupt */ +} +#endif From 4d5d3eb9e6d88c66f923239e69fb5f2e5788acbb Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 7 Jan 2020 00:35:38 +0100 Subject: [PATCH 2/4] boards/msba2: hook up i2c I2C is not used by any chip on the board, but I2C2 is availiable on the JP3 connector (shared with UART2). - SDA: P0.10 - SCL: P0.11 --- boards/msba2/Makefile.features | 1 + boards/msba2/include/periph_conf.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/boards/msba2/Makefile.features b/boards/msba2/Makefile.features index 1f563e7c87fc..7d6f4b673dff 100644 --- a/boards/msba2/Makefile.features +++ b/boards/msba2/Makefile.features @@ -2,6 +2,7 @@ CPU = lpc2387 # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_adc +FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_spi diff --git a/boards/msba2/include/periph_conf.h b/boards/msba2/include/periph_conf.h index 59108bfd4dd6..b75ff5a0b1b7 100644 --- a/boards/msba2/include/periph_conf.h +++ b/boards/msba2/include/periph_conf.h @@ -155,6 +155,25 @@ static const adc_conf_t adc_config[] = { #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ +/** + * @name I2C configuration + * @{ + */ +static const i2c_conf_t i2c_config[] = { + { /* JP3 */ + .dev = I2C2, + .speed = I2C_SPEED_NORMAL, + .irq_prio = 5, + .pinsel_sda = 0, + .pinsel_scl = 0, + .pinsel_msk_sda = BIT21, /* P0.10 */ + .pinsel_msk_scl = BIT23, /* P0.11 */ + }, +}; + +/* used in arithmetic preprocessor expression, so no ARRAY_SIZE() */ +#define I2C_NUMOF (1) +/** @} */ #ifdef __cplusplus } From 9d1a2b5fb43506e21b6adfee271df93aa07f669e Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 14 Jan 2020 23:21:38 +0100 Subject: [PATCH 3/4] boards/mcb2388: add I2C config The pins for I2C0 and I2C1 are available on the board, nothing is wired up to them. --- boards/mcb2388/Makefile.features | 1 + boards/mcb2388/include/periph_conf.h | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/boards/mcb2388/Makefile.features b/boards/mcb2388/Makefile.features index b18154210e92..95cb8ca31195 100644 --- a/boards/mcb2388/Makefile.features +++ b/boards/mcb2388/Makefile.features @@ -3,6 +3,7 @@ CPU_MODEL = lpc2388 # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_adc +FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer diff --git a/boards/mcb2388/include/periph_conf.h b/boards/mcb2388/include/periph_conf.h index 9ca887bf128b..ef37190cadab 100644 --- a/boards/mcb2388/include/periph_conf.h +++ b/boards/mcb2388/include/periph_conf.h @@ -101,6 +101,33 @@ static const adc_conf_t adc_config[] = { }; #define ADC_NUMOF (1) + +/** + * @name I2C configuration + * @{ + */ +static const i2c_conf_t i2c_config[] = { + { + .dev = I2C0, + .speed = I2C_SPEED_NORMAL, + .irq_prio = 5, + .pinsel_sda = 1, + .pinsel_scl = 1, + .pinsel_msk_sda = BIT22, /* P0.27 */ + .pinsel_msk_scl = BIT24, /* P0.28 */ + }, + { + .dev = I2C1, + .speed = I2C_SPEED_NORMAL, + .irq_prio = 5, + .pinsel_sda = 1, + .pinsel_scl = 1, + .pinsel_msk_sda = BIT6 | BIT7, /* P0.19 */ + .pinsel_msk_scl = BIT8 | BIT9, /* P0.20 */ + }, +}; + +#define I2C_NUMOF (2) /** @} */ #ifdef __cplusplus From 00131bb7459bc8652b6c9c5960f5202791e5881f Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 26 Feb 2020 21:06:04 +0100 Subject: [PATCH 4/4] drivers/at24mac: include kernel_defines.h We need that header file for the ARRAY_SIZE() macro. --- drivers/at24mac/at24mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/at24mac/at24mac.c b/drivers/at24mac/at24mac.c index d23e8e03d45a..e377bea3dc94 100644 --- a/drivers/at24mac/at24mac.c +++ b/drivers/at24mac/at24mac.c @@ -19,6 +19,7 @@ */ #include +#include "kernel_defines.h" #include "at24mac.h" #include "at24mac_params.h"