Skip to content

Commit 1433e97

Browse files
authored
I2C slave and scanning (#108)
* added examples * i2c slave and scanning * Create README.md
1 parent ada82c0 commit 1433e97

File tree

6 files changed

+343
-25
lines changed

6 files changed

+343
-25
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
I2C Minimal Slave - CH32 I2C Slave example
3+
4+
Show the minimal code required to implement an I2C slave device with these features:
5+
- handle I2C scanning (i.e. acknowledge data-less transaction)
6+
- handle receiving data
7+
- return data requested by master
8+
- blink LED on PA2 according transfered value
9+
10+
Compiled for CH32V003J4M6 (SOP8) using Arduino IDE v2.3.2, CH32 core v1.0.4.
11+
Optimize: Smallest (-Os default), Debug symbols: none, no UART: //#define UART_MODULE_ENABLED
12+
Note - enable I2C slave functionality in /libraries/Wire/src/utility/twi.h
13+
#define OPT_I2C_SLAVE 1
14+
15+
Using those options this sketch uses 9424 bytes (57%) of program storage space. Maximum is 16384 bytes.
16+
Global variables use 580 bytes (28%) of dynamic memory, leaving 1468 bytes for local variables. Maximum is 2048 bytes.
17+
*/
18+
19+
#include <Wire.h>
20+
#define MY_I2C_ADDRESS 0x33
21+
22+
#undef LED_BUILTIN
23+
#define LED_BUILTIN PA2
24+
uint32_t _nBlinkSpeed=500;
25+
26+
void ReceiveEvent(int nNumBytes) {
27+
// receive value is stored to set the speed of blinking
28+
_nBlinkSpeed=0;
29+
while(nNumBytes>0)
30+
{
31+
_nBlinkSpeed<<=8;
32+
_nBlinkSpeed|=Wire.read();
33+
nNumBytes--;
34+
}
35+
}
36+
37+
void RequestEvent() {
38+
// returned 32-bit value is the current speed of blinking
39+
Wire.write((const uint8_t *)&_nBlinkSpeed, sizeof(_nBlinkSpeed));;
40+
}
41+
42+
void setup() {
43+
pinMode(LED_BUILTIN, OUTPUT); // Initialize digital pin LED_BUILTIN as an output.
44+
Wire.begin(MY_I2C_ADDRESS);
45+
// Note: enable I2C slave functionality in /libraries/Wire/src/utility/twi.h to prevent error message for next two lines
46+
Wire.onReceive(ReceiveEvent);
47+
Wire.onRequest(RequestEvent);
48+
}
49+
50+
void loop() {
51+
static uint32_t uStart=millis();
52+
if(millis()-uStart > _nBlinkSpeed)
53+
{ // blink the LED by reversing its state
54+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
55+
uStart=millis();
56+
}
57+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# I2C Scanner
2+
Original I2C Scanner example by Nick Gammon
3+
I2C Scanner - Written by Nick Gammon - Date: 20th April 2011 [source](http://arduino-info.wikispaces.com/LCD-Blue-I2C).
4+
5+
Demonstrates CH32 Support for I2C scanning using Wire.endTransmission() without sending data.
6+
To enable scanning these changes are required in libraries/Wire/src/utility/twi.c :
7+
- timeout on an addresses should release the bus
8+
- allow only sending the address (without actual data)
9+
- smaller timeout: I2C_TIMEOUT_TICK 25 (was 100ms)
10+
11+
Note: Currently there's no support for [Wire.setWireTimeout(timeout, reset_on_timeout)](https://www.arduino.cc/reference/en/language/functions/communication/wire/setwiretimeout/).
12+
Inspiration from [i2c_scanner](https://github.com/mockthebear/easy-ch32v003/tree/main/examples/i2c_scanner) by @mockthebear.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
// I2C Scanner
3+
// Written by Nick Gammon
4+
// Date: 20th April 2011
5+
6+
// source: http://arduino-info.wikispaces.com/LCD-Blue-I2C
7+
8+
// MMOLE: CH32 Support I2C scanning using Wire.endTransmission() without sending data
9+
// CH32 changes required in libraries/Wire/src/utility/twi.c
10+
// - timeout on an addresses should release the bus
11+
// - allow only sending the address (without actual data)
12+
// - smaller timeout: I2C_TIMEOUT_TICK 25 (was 100ms)
13+
// Note: Currently there's no support for Wire.setWireTimeout(timeout, reset_on_timeout)
14+
// https://www.arduino.cc/reference/en/language/functions/communication/wire/setwiretimeout/
15+
// Inspiration from https://github.com/mockthebear/easy-ch32v003/tree/main/examples/i2c_scanner
16+
17+
18+
19+
#include <Wire.h>
20+
21+
void setup() {
22+
Serial.begin (115200);
23+
24+
// Leonardo: wait for serial port to connect
25+
while (!Serial)
26+
{
27+
}
28+
29+
Serial.println ();
30+
Serial.println ("I2C scanner. Scanning ...");
31+
32+
Wire.begin();
33+
while(true)
34+
{
35+
36+
byte count = 0;
37+
for (byte i = 8; i < 120; i++)
38+
{
39+
Wire.beginTransmission (i);
40+
if (Wire.endTransmission () == 0)
41+
{
42+
Serial.print ("Found address: ");
43+
Serial.print (i, DEC);
44+
Serial.print (" (0x");
45+
Serial.print (i, HEX);
46+
Serial.println (")");
47+
count++;
48+
delay (1); // maybe unneeded?
49+
} // end of good response
50+
} // end of for loop
51+
Serial.println ("Done.");
52+
Serial.print ("Found ");
53+
Serial.print (count, DEC);
54+
Serial.println (" device(s).");
55+
delay(1000);
56+
Serial.println ("Scanning again...");
57+
}
58+
} // end of setup
59+
60+
void loop() {}

libraries/Wire/src/Wire.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,13 @@ void TwoWire::begin(uint8_t address, bool generalCall, bool NoStretchMode)
9393

9494
if (_i2c.isMaster == 0)
9595
{
96+
#if OPT_I2C_SLAVE
97+
// MMOLE: these four lines were all commented
9698
// i2c_attachSlaveTxEvent(&_i2c, reinterpret_cast<void(*)(i2c_t*)>(&TwoWire::onRequestService));
9799
// i2c_attachSlaveRxEvent(&_i2c, reinterpret_cast<void(*)(i2c_t*, uint8_t*, int)>(&TwoWire::onReceiveService));
98-
// i2c_attachSlaveTxEvent(&_i2c, onRequestService);
99-
// i2c_attachSlaveRxEvent(&_i2c, onReceiveService);
100+
i2c_attachSlaveTxEvent(&_i2c, onRequestService);
101+
i2c_attachSlaveRxEvent(&_i2c, onReceiveService);
102+
#endif
100103
}
101104
}
102105

@@ -277,11 +280,13 @@ size_t TwoWire::write(uint8_t data)
277280
txDataSize++;
278281
}
279282
} else {
283+
#if OPT_I2C_SLAVE
280284
// in slave send mode
281285
// reply to master
282286
if (i2c_slave_write(&_i2c, &data, 1) != I2C_OK) {
283287
ret = 0;
284288
}
289+
#endif // #if OPT_I2C_SLAVE
285290
}
286291
return ret;
287292
}
@@ -309,11 +314,13 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity)
309314
txDataSize += quantity;
310315
}
311316
} else {
317+
#if OPT_I2C_SLAVE
312318
// in slave send mode
313319
// reply to master
314320
if (i2c_slave_write(&_i2c, (uint8_t *)data, quantity) != I2C_OK) {
315321
ret = 0;
316322
}
323+
#endif // #if OPT_I2C_SLAVE
317324
}
318325
return ret;
319326
}
@@ -372,6 +379,7 @@ void TwoWire::flush(void)
372379

373380

374381
// behind the scenes function that is called when data is received
382+
#if OPT_I2C_SLAVE
375383
void TwoWire::onReceiveService(i2c_t *obj)
376384
{
377385
uint8_t *inBytes = (uint8_t *) obj->i2cTxRxBuffer;
@@ -413,7 +421,9 @@ void TwoWire::onRequestService(i2c_t *obj)
413421
TW->user_onRequest();
414422
}
415423
}
424+
#endif // #if OPT_I2C_SLAVE
416425

426+
#if OPT_I2C_SLAVE
417427
// sets function called on slave write
418428
void TwoWire::onReceive(cb_function_receive_t function)
419429
{
@@ -425,6 +435,7 @@ void TwoWire::onRequest(cb_function_request_t function)
425435
{
426436
user_onRequest = function;
427437
}
438+
#endif // #if OPT_I2C_SLAVE
428439

429440

430441

0 commit comments

Comments
 (0)