Select one of the symbols to view example projects that use it.
 
Outline
#include "pico/i2c_slave.h"
#include "hardware/irq.h"
i2c_slave
i2c_slaves
i2c_slave_irq_handler()
i2c_slave_init(i2c_inst_t *, uint8_t, i2c_slave_handler_t)
i2c_slave_deinit(i2c_inst_t *)
Files
loading...
SourceVuRaspberry Pi Pico SDK and ExamplesPicoSDKsrc/rp2_common/pico_i2c_slave/i2c_slave.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * Copyright (c) 2021 Valentin Milea <valentin.milea@gmail.com> * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */ #include "pico/i2c_slave.h" #include "hardware/irq.h" typedef struct i2c_slave { i2c_slave_handler_t handler; bool transfer_in_progress; ...} i2c_slave_t; static i2c_slave_t i2c_slaves[2]; static void __isr __not_in_flash_func(i2c_slave_irq_handler)(void) { uint i2c_index = __get_current_exception() - VTABLE_FIRST_IRQ - I2C0_IRQ; i2c_slave_t *slave = &i2c_slaves[i2c_index]; i2c_inst_t *i2c = i2c_get_instance(i2c_index); i2c_hw_t *hw = i2c_get_hw(i2c); uint32_t intr_stat = hw->intr_stat; if (intr_stat == 0) { return; }if (intr_stat == 0) { ... } bool do_finish_transfer = false; if (intr_stat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { hw->clr_tx_abrt; do_finish_transfer = true; }if (intr_stat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { ... } if (intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) { hw->clr_start_det; do_finish_transfer = true; }if (intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) { ... } if (intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { hw->clr_stop_det; do_finish_transfer = true; }if (intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { ... } if (do_finish_transfer && slave->transfer_in_progress) { slave->handler(i2c, I2C_SLAVE_FINISH); slave->transfer_in_progress = false; }if (do_finish_transfer && slave->transfer_in_progress) { ... } if (intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { slave->transfer_in_progress = true; slave->handler(i2c, I2C_SLAVE_RECEIVE); }if (intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { ... } if (intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { hw->clr_rd_req; slave->transfer_in_progress = true; slave->handler(i2c, I2C_SLAVE_REQUEST); }if (intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { ... } ...} void i2c_slave_init(i2c_inst_t *i2c, uint8_t address, i2c_slave_handler_t handler) { assert(i2c == i2c0 || i2c == i2c1); assert(handler != NULL); uint i2c_index = i2c_hw_index(i2c); i2c_slave_t *slave = &i2c_slaves[i2c_index]; slave->handler = handler; // Note: The I2C slave does clock stretching implicitly after a RD_REQ, while the Tx FIFO is empty. // There is also an option to enable clock stretching while the Rx FIFO is full, but we leave it // disabled since the Rx FIFO should never fill up (unless slave->handler() is way too slow). i2c_set_slave_mode(i2c, true, address); i2c_hw_t *hw = i2c_get_hw(i2c); // unmask necessary interrupts hw->intr_mask = I2C_IC_INTR_MASK_M_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_INTR_MASK_M_TX_ABRT_BITS | I2C_IC_INTR_MASK_M_STOP_DET_BITS | I2C_IC_INTR_MASK_M_START_DET_BITS; // enable interrupt for current core uint num = I2C0_IRQ + i2c_index; irq_set_exclusive_handler(num, i2c_slave_irq_handler); irq_set_enabled(num, true); }{ ... } void i2c_slave_deinit(i2c_inst_t *i2c) { assert(i2c == i2c0 || i2c == i2c1); uint i2c_index = i2c_hw_index(i2c); i2c_slave_t *slave = &i2c_slaves[i2c_index]; assert(slave->handler); // should be called after i2c_slave_init() slave->handler = NULL; slave->transfer_in_progress = false; uint num = I2C0_IRQ + i2c_index; irq_set_enabled(num, false); irq_remove_handler(num, i2c_slave_irq_handler); i2c_hw_t *hw = i2c_get_hw(i2c); hw->intr_mask = I2C_IC_INTR_MASK_RESET; i2c_set_slave_mode(i2c, false, 0); }{ ... }
Details