For the fun of it I was looking at the Wire library for the OpenCR board. My initial reason for looking is to add the Wire1 object that would use pins on the expansion connector (default pins 50, 51). Which is when I figured out that the Wire library is not currently using the underlying hardware I2C system, but doing software bitbanging). So I started working on trying to implement the Wire library using the underlying hardware system.
I have made some progress on this. I have discussed some of this on the OpenCR github project as an issue:
As well as on the Robotis forum:
@ROBOTIS-Will suggested I post up here as well so…
I believe I have most of the Wire Master code working, including Wire1 object, although still need to test (and probably) fix some issues associated with send_stop and restart code. Need to find or create test sketch for this.
So started working on trying to implement the Wire slave code. That is where your sketch does stuff like:
Wire1.onReceive(&process_OnReceive);
Wire1.onRequest(&process_onRequest);
Wire1.begin(SLAVE_ADDRESS); // Start up Wire1 as a slave
Where the user function process_OnReceive will be called when the I2C Master does a transmission to the slave address. and the onRequest will be called when the master does a requestFrom…
So I put in some initial code that I thought should setup the receive interrupt in my slave begin method:
HAL_I2C_Slave_Receive_IT(hi2c_, rxBuffer, sizeof(rxBuffer));
And setup test case to trigger it, and then ran it and nothing happened. That is the HAL_I2C_EV_IRQHandler was not called. I verified this by setting up to have an IO pin go high when this function was called and go low when it was to return… Nothing happened.
Finally figured out there was no glue(code) in system, that setup the I2C interrupts, they were set to the default handler, and they were not enabled. So I added code similar to how UARTS do it and finally later yesterday, the HAL handler is begin called
Currently I am testing this with simple test app, where on my OpenCR board I have the Wire (Master) pins connected to the Wire1 (Slave) pins and the test app simply waits for user input on Serial. When it receives it it sends the data out over Wire. My Wire1 onReceive method then echoes this data back on to Serial…
Current sketch (Still can not attach zip files here…)
#include <Wire.h>
#define SLAVE_ADDRESS 0x66
//
void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
pinMode(12, OUTPUT);
digitalWrite(12, LOW);
while (!Serial && millis() < 5000) ;
Serial.begin(115200);
delay(400);
Serial.println("Start Wire to Wire1 test");
Wire1.onReceive(&process_OnReceive);
Wire1.onRequest(&process_onRequest);
Wire1.begin(SLAVE_ADDRESS); // Start up Wire1 as a slave
Wire.setClock(400000); // Lets try 400K speed
Wire.begin(); // Start up Wire as master
Serial.printf("I2C1 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C1->ISR, I2C1->CR1,
I2C1->CR2, I2C1->OAR1);
Serial.printf("I2C2 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C2->ISR, I2C2->CR1,
I2C2->CR2, I2C2->OAR1);
#if 0
// Quick hack to see if I see anything
for (byte address = 0; address < 127; address++) {
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
if (error == 0) Serial.printf("Found something: %x\n", address);
}
#endif
for(int i=0;i<4;i++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, (GPIO_PinState)1); // digitalWrite(13, Low);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, (GPIO_PinState)0); // digitalWrite(12, low);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, (GPIO_PinState)0); // digitalWrite(13, Low);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, (GPIO_PinState)1); // digitalWrite(12, low);
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, (GPIO_PinState)0); // digitalWrite(12, low);
}
void loop() {
Serial.print("Enter Text to send: ");
while (Serial.available() == 0) ;
Wire.beginTransmission(SLAVE_ADDRESS);
int ch;
while((ch = Serial.read()) != -1) {
if ((ch >= ' ') && (ch <= '~')) Wire.write(ch);
Serial.write(ch);
}
Wire.endTransmission();
delay(5);
#if 0
Serial.printf("I2C1 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C1->ISR, I2C1->CR1,
I2C1->CR2, I2C1->OAR1);
Serial.printf("I2C2 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C2->ISR, I2C2->CR1,
I2C2->CR2, I2C2->OAR1);
#endif
// Lets see what happens when we call Wire.requestFrom
uint8_t cb = Wire.requestFrom(SLAVE_ADDRESS, 4);
Serial.printf("Wire.requestFrom return value: %d\n", cb);
Serial.printf("I2C1 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C1->ISR, I2C1->CR1,
I2C1->CR2, I2C1->OAR1);
Serial.printf("I2C2 ISR:%x CR1:%x CR2:%x OAR1:%x\n", I2C2->ISR, I2C2->CR1,
I2C2->CR2, I2C2->OAR1);
}
void process_OnReceive(int num_bytes) {
Serial.printf("OnRecieve Called: %d = ", num_bytes);
while (Wire1.available()) {
Serial.write(Wire1.read());
}
Serial.println();
}
void process_onRequest() {
Serial.println("onRequest called");
}
Current status
The current WIP code is up on my fork/branch on github:
https://github.com/KurtE/OpenCR/tree/Wire-Library
Currently this branch is based off of my SPI fork, which has been merged into the main develop branch, so soon I will try to rebase this off of the develop branch… As I am not a git wizard, I may do this by copying the changed code to safe place, switch to develop branch, create new branch off of develop and then copy in changed code…
As I mentioned the onReceive code appears to be functioning (at least for this test case), Figured out that I needed to reissue the call to HAL_I2C_Slave_Receive_IT after each time I received something.
so starting to try to setup code for the onRequest. Simple test added as part of code above, where after I send data to slave I ask the slave for 4 bytes.
Some output from test app:
Start Wire to Wire1 test
I2C1 ISR:1 CR1:1 CR2:2000000 OAR1:0
I2C2 ISR:1 CR1:fd CR2:2000000 OAR1:80cc
Enter Text to send: abcd
OnRecieve Called: 4 = abcd
Wire.requestFrom return value: 0
I2C1 ISR:8001 CR1:1 CR2:20404cc OAR1:0
I2C2 ISR:cd8003 CR1:fd CR2:2000000 OAR1:80cc
Enter Text to send:
Right now trying to figure out how to setup the glue for doing either onReceive or onRequest.
From the above output, I do see that the Master is trying to talk to Slave after the call returns, the status of the two wire objects both show busy.
The shows that the TXIS bit is set saying that the Wire object wants data. But currently the CR1 is setup for Receive so the HAL_I2C_EV_IRHandler will not call of to the I2C_SlaveTransmit_ISR.
Note: the slave transmit and receive call both use the same internal buffers, so not sure if it makes sense to enable both at the same time? That is I could have begin code in addition to calling: HAL_I2C_Slave_Receive_IT also call of to HAL_I2C_Slave_Transmit_IT
I think that would be problematic, with the Wire library as I believe the I2C_SlaveTransmit_ISR just wants to send the data that currently sits in it’s own buffer and not call of that time to client code to tell it what to send…
Suggestions? Am I missing something obvious?
Thanks