Using MSPf5529 with UART returns spacing cedilla in Mac - msp430

I'm trying to use the MSPF5529 with my mac. I've downloaded code composer studio and can easily access the chip as well as blink lights and any other application I need.
The goal is for me to print a message using UART through serial communication on my Mac. I am currently using an application called "goSerial" in order to communicate with the chip. My code below initializes UART, takes in a single character, and then it is supposed to print out a character, and then blink a light. However, instead, the code takes in the character, and prints out a strange symbol, called a spacing cedilla, with a hex value of 0xFC, and then blinks the light.
This symbol appears regardless of which character I put into the MSP430 buffer.
My code is listed below. Has anyone had this problem before? How do I solve this?
void Init_UART(void);
void OUTA_UART(unsigned char A);
unsigned char INCHAR_UART(void);
#include "msp430f5529.h"
#include "stdio.h"
int main(void){
volatile unsigned char a;
volatile unsigned int i;
WDTCTL = WDTPW + WDTHOLD;
Init_UART();
a=INCHAR_UART();
a=INCHAR_UART();
OUTA_UART(a);
// go blink the light to indicate code is running
P1DIR |= 0x01;
for (;;){
P1OUT ^= 0x01; i = 10000;
do i--;
while (i != 0); }
}
void OUTA_UART(unsigned char A){
while ((UCA1STAT&UCBUSY));
// send the data to the transmit buffer
UCA1TXBUF =A;
}
unsigned char INCHAR_UART(void){
while ((UCA1STAT&UCBUSY) == 0);
// go get the char from the receive buffer
return (UCA1RXBUF);
}
void Init_UART(void){
P4SEL |= 0x30; // Port 4.4 and port 4.5 controls the transfer
UCA1CTL1|= UCSWRST; // Put state machine in reset
UCA1CTL1|= UCSSEL_1; //Choose 32765Hz
UCA0BR0=3; // Baud rate = 9600
UCA0BR1=0; // Choose 32765 hz
UCA1MCTL=0x06; // Modulation UCBRSx=3, UCBFx = 0
UCA1CTL1 &= ~UCSWRST; // Put USCI in operation mode
}

The UCBUSY flag is not very useful, and cannot be used like this.
That a byte has been received is indicated by UCRXIFG:
while (!(UCA1IFG & UCRXIFG)) ;
return UCA1RXBUF;
That a byte can be sent is indicated by UCTXIFG:
while (!(UCA1IFG & UCTXIFG)) ;
UCA1TXBUF = a;

Related

ESP8266 Wifi-Sniffer doesn't collect SSIDs (Probe Request / Probe Frame)

I'm trying to get the following project running:
https://github.com/kalanda/esp8266-sniffer
The project is about Probe Frame / Probe Request. It let's a simple ESP8266 act like a WLAN Router, and collect all incoming Probe Frames. Every Probe Frame should include the MAC address of the device, and one SSID of it's saved networks. That's it.
I have copied the code of the project on my ESP8266.
I have 3 different smartphones laying around.
So now, when I look in the Serial Monitor, I should see all the packages from my 3 smartphones, every package should include the MAC address of the smartphone, and also one of the saved SSID's, which it was connected to in the past.
I see everything, except for the SSID's.
I can see the Probe Frames, coming from my different smartphones, but the SSID's are just blank.
Anyone has a idea?
Here is the complete code of the project.
Also, I have attached a screenshot of my Serial Monitor output. I have just painted the MAC addresses of my smartphones green. So as you can see, no SSIDs.
I'm very thankful for EVERY help or idea!
Thanks in advance,
EMHA.
SCREENSHOT OF SERIAL MONITOR OUTPUT
#include <Arduino.h>
extern "C" {
#include <user_interface.h>
}
#define DATA_LENGTH 112
#define TYPE_MANAGEMENT 0x00
#define TYPE_CONTROL 0x01
#define TYPE_DATA 0x02
#define SUBTYPE_PROBE_REQUEST 0x04
struct RxControl {
signed rssi:8; // signal intensity of packet
unsigned rate:4;
unsigned is_group:1;
unsigned:1;
unsigned sig_mode:2; // 0:is 11n packet; 1:is not 11n packet;
unsigned legacy_length:12; // if not 11n packet, shows length of packet.
unsigned damatch0:1;
unsigned damatch1:1;
unsigned bssidmatch0:1;
unsigned bssidmatch1:1;
unsigned MCS:7; // if is 11n packet, shows the modulation and code used (range from 0 to 76)
unsigned CWB:1; // if is 11n packet, shows if is HT40 packet or not
unsigned HT_length:16;// if is 11n packet, shows length of packet.
unsigned Smoothing:1;
unsigned Not_Sounding:1;
unsigned:1;
unsigned Aggregation:1;
unsigned STBC:2;
unsigned FEC_CODING:1; // if is 11n packet, shows if is LDPC packet or not.
unsigned SGI:1;
unsigned rxend_state:8;
unsigned ampdu_cnt:8;
unsigned channel:4; //which channel this packet in.
unsigned:12;
};
struct SnifferPacket{
struct RxControl rx_ctrl;
uint8_t data[DATA_LENGTH];
uint16_t cnt;
uint16_t len;
};
// Declare each custom function (excluding built-in, such as setup and loop) before it will be called.
// https://docs.platformio.org/en/latest/faq.html#convert-arduino-file-to-c-manually
static void showMetadata(SnifferPacket *snifferPacket);
static void ICACHE_FLASH_ATTR sniffer_callback(uint8_t *buffer, uint16_t length);
static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data);
static void getMAC(char *addr, uint8_t* data, uint16_t offset);
void channelHop();
static void showMetadata(SnifferPacket *snifferPacket) {
unsigned int frameControl = ((unsigned int)snifferPacket->data[1] << 8) + snifferPacket->data[0];
uint8_t version = (frameControl & 0b0000000000000011) >> 0;
uint8_t frameType = (frameControl & 0b0000000000001100) >> 2;
uint8_t frameSubType = (frameControl & 0b0000000011110000) >> 4;
uint8_t toDS = (frameControl & 0b0000000100000000) >> 8;
uint8_t fromDS = (frameControl & 0b0000001000000000) >> 9;
// Only look for probe request packets
if (frameType != TYPE_MANAGEMENT ||
frameSubType != SUBTYPE_PROBE_REQUEST)
return;
Serial.print("RSSI: ");
Serial.print(snifferPacket->rx_ctrl.rssi, DEC);
Serial.print(" Ch: ");
Serial.print(wifi_get_channel());
char addr[] = "00:00:00:00:00:00";
getMAC(addr, snifferPacket->data, 10);
Serial.print(" Peer MAC: ");
Serial.print(addr);
uint8_t SSID_length = snifferPacket->data[25];
Serial.print(" SSID: ");
printDataSpan(26, SSID_length, snifferPacket->data);
Serial.println();
}
/**
* Callback for promiscuous mode
*/
static void ICACHE_FLASH_ATTR sniffer_callback(uint8_t *buffer, uint16_t length) {
struct SnifferPacket *snifferPacket = (struct SnifferPacket*) buffer;
showMetadata(snifferPacket);
}
static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data) {
for(uint16_t i = start; i < DATA_LENGTH && i < start+size; i++) {
Serial.write(data[i]);
}
}
static void getMAC(char *addr, uint8_t* data, uint16_t offset) {
sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", data[offset+0], data[offset+1], data[offset+2], data[offset+3], data[offset+4], data[offset+5]);
}
#define CHANNEL_HOP_INTERVAL_MS 1000
static os_timer_t channelHop_timer;
/**
* Callback for channel hoping
*/
void channelHop()
{
// hoping channels 1-13
uint8 new_channel = wifi_get_channel() + 1;
if (new_channel > 13) {
new_channel = 1;
}
wifi_set_channel(new_channel);
}
#define DISABLE 0
#define ENABLE 1
void setup() {
// set the WiFi chip to "promiscuous" mode aka monitor mode
Serial.begin(115200);
delay(10);
wifi_set_opmode(STATION_MODE);
wifi_set_channel(1);
wifi_promiscuous_enable(DISABLE);
delay(10);
wifi_set_promiscuous_rx_cb(sniffer_callback);
delay(10);
wifi_promiscuous_enable(ENABLE);
// setup the channel hoping callback timer
os_timer_disarm(&channelHop_timer);
os_timer_setfn(&channelHop_timer, (os_timer_func_t *) channelHop, NULL);
os_timer_arm(&channelHop_timer, CHANNEL_HOP_INTERVAL_MS, 1);
}
void loop() {
delay(10);
}
The probe requests that you are recording most probably do not even contain an SSID.
Directed probes (targetting a specific SSID) came somewhat out of fashion, mainly for privacy reasons (clients are revealing the SSID they are looking for). What you are seeing are broadcast probe requests. Basically the same thing, but difference is that they do contain an SSID. All access points that receive such probe request frames reply with a probe response, this way allowing the client to aggregate a list of networks in range.
Directed probe requests nowadays are only sent just right before a (re-) connection is established. So maybe it helps if you disconnect/reconnect some clients from the Wi-Fi network to test your code?

I'm having trouble implementing the Atmega328 timer into my arduino networking

I am trying to implement error correction over an r/f communication between two arduinos. I tried adding a timer to it, in order to create a packet resend, but whenever it gets past the first send, it starts printing garbage ad infinity instead of doing the timer interrupt.
I tried messing around with the inside loop conditions some as well as trying to figure out what was wrong with the timer, but I couldn't figure it out. The problem seems to happen right around the first serial print, which is strange, because that part of the code is mostly unchanged.
(packets is a structure of two ints)
#include <ELECHOUSE_CC1101.h>
#include "packets.h"
// These examples are from the Electronics Cookbook by Simon Monk
// Connections (for an Arduino Uno)
// Arduino CC1101
// GND GND
// 3.3V VCC
// 10 CSN/SS **** Must be level shifted to 3.3V
// 11 SI/MOSI **** Must be level shifted to 3.3V
// 12 SO/MISO
// 13 SCK **** Must be level shifted to 3.3V
// 2 GD0
const int n = 61;
unsigned short int sequence = 0;
byte buffer[n] = "";
void setup() {
Serial.begin(9600);
Serial.println("Set line ending to New Line in Serial Monitor.");
Serial.println("Enter Message");
ELECHOUSE_cc1101.Init(F_433); // set frequency - F_433, F_868, F_965 MHz
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 0xFFFF; // Max value for overflow for now
TCCR1B |= (1 << CS12); // 256 prescaler
interrupts(); // enable all interrupts
}
Packet pckt, recieve;
ISR(TIMER1_OVR_vect){ // timer compare interrupt service routine
//Resend packet
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
recieve.seqNum = buffer[n];
Serial.println("Interrupt");
}
void loop() {
if (Serial.available()) {
pckt.data = Serial.readBytesUntil('\n', buffer, n);
pckt.seqNum = sequence;
buffer[pckt.data] = '\0';
buffer[n-1] = pckt.seqNum;
Serial.println((char *)buffer);
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
TCNT1 = 0; // clear timer
TIMSK1 |= (1 << TOIE0); // enable timer compare interrupt
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
while (recieve.seqNum <= sequence) {
}
TIMSK1 &= ~(1 << TOIE0); // turn off the timer interrupt
}
}
Sending data takes too long for interrupts. You should keep calls to send and receive buffers of data within the loop() function call tree. For example, sending a 12 bytes message via UART at 9600 bauds can take up to about 12ms.
You can use the timer interrupt to decrement a timeout counter, as is usually done on micro controllers, or use the millis() function to handle timings, as is easily done on Arduino.
I suggest you use the millis() function to compute timeouts.
example:
/* ... */
// I could not figure out what you were trying to do with
// pckt.seqNum.... Putting it at the end of the buffer
// makes no sense, so I've left it out.
// Moreover, its size is 2, so placing it at buffer[n-1] overflows the buffer...
enum machineState {
waitingForSerial,
waitingForResponse,
};
unsigned int time_sent; // Always use unsigned for variables holding millis()
// can use unsigned char for timeouts of 255
// milliseconds or less. unsigned int is good for about
// 65.535 seconds or less.
machineState state = waitingForSerial;
void loop()
{
switch(state)
{
case waitingForSerial:
pckt.data = Serial.readBytesUntil('\n', buffer, sizeof(buffer));
if (pckt.data > 0)
{
++pckt.seqNum;
Serial.write(buffer, pckt.data);
ELECHOUSE_cc1101.SetReceive();
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
state = waitingForResponse;
}
break;
case waitingForResponse:
if (ELECHOUSE_cc1101.CheckReceiveFlag())
{
auto len = ELECHOUSE_cc1101.ReceiveData(buffer)) // can use C++17 with duinos!!!
Serial.print("cc1101: ");
Serial.write(buffer, len);
state = waitingForSerial; // wait for another command from PC
}
// 1 second timeout, note the cast and subtraction, this is to avoid any
// issues with rollover of the millis() timestamp.
else if ((unsigned int)millis() - time_sent > 1000)
{
// resend ... stays stuck this way.
Serial.println("Retrying :(");
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
}
break;
default:
state = waitingForSerial;
Serial.println("unhandled state");
break;
}
}

Receiving data from SIM808

I am trying to use SIM808 module but I have no response even after sending only "AT". I am using 5V/2.5A AC/DC adapter. The board (ecb-v3.2) is rather connected well because two diodes are on all the time and one is blinking every three seconds. I tried my UART code by sending and receiving data from uC to PC and it worked. I also tried to display some data in different parts of my code to find a line with a bug. I think that problem is in the while loop in which I am waiting for receiving a single char from SIM808 module. I marked this line in the code (in function UART_RxChar()). I am using two UARTs in my code, one for sending data between uC and PC (channel 0 in the code) and second for sending data between uC and SIM808 (channel 1), but I checked both versions on my computer. This is my code:
#define F_OSC 7372800UL
#define BAUD 115200
#define ubrr ((F_OSC/16/BAUD)-1)
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
void UART_TxString(char *string_ptr, uint8_t channel);
void UART_Init( uint8_t channel )
{
if ( channel == 0)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<TXEN0) | (1<<RXEN0);
/* Set frame format: 8data, 1stop bit */
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
}
else
{
/*Set baud rate */
UBRR1H = (unsigned char)(ubrr>>8);
UBRR1L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR1B = (1<<TXEN1) | (1<<RXEN1);
/* Set frame format: 8data, 1stop bit */
UCSR1C = (1<<UCSZ10)|(1<<UCSZ11);
}
}
char UART_RxChar( uint8_t channel )
{
if ( channel == 0 )
{
while((UCSR0A & (1<<RXC0))==0); // Wait till the data is received
return(UDR0); // return the received char
}
else
{
//Here is the problem. The condition in the loop is always true.
while((UCSR1A & (1<<RXC1))==0); // Wait till the data is received
return(UDR1); // return the received char
}
}
void UART_TxChar(char ch, uint8_t channel)
{
if ( channel == 0)
{
while((UCSR0A & (1<<UDRE0))==0); // Wait till Transmitter(UDR) register becomes Empty
UDR0 =ch; // Load the data to be transmitted
}
else
{
while((UCSR1A & (1<<UDRE1))==0); // Wait till Transmitter(UDR) register becomes Empty
UDR1 =ch; // Load the data to be transmitted
UART_TxChar(ch,0);
}
}
void UART_TxString(char *string_ptr, uint8_t channel)
{
while(*string_ptr)
UART_TxChar(*string_ptr++, channel);
}
void UART_RxString(char *string_ptr, uint8_t channel)
{
char ch;
while(1)
{
ch=UART_RxChar(channel); //Reaceive a char
UART_TxChar(ch, channel); //Echo back the received char
if((ch=='\r') || (ch=='\n')) //read till enter key is pressed
{ //once enter key is pressed
*string_ptr=0; //null terminate the string
break; //and break the loop
}
*string_ptr=ch; //copy the char into string.
string_ptr++; //and increment the pointer
}
}
int main(void)
{
UART_Init(0);
UART_Init(1);
initLCD();
UART_TxString("\r\nstart", 0);
while(1)
{
char ans[15] = "";
DDRE = 0xff;
UART_TxString("AT\r\n",1);
DDRE = 0x00;
UART_RxString(ans,1);
_delay_ms(2000);
}
}
I also checked all possibilities sending: AT\r", "AT\n", "AT\r\n", "AT\n\r.
Thank you in advance for any help.
The problem is you are echoing the received character back to SIM808 module on line
UART_TxChar(ch, channel); //Echo back the received char
this may confuse SIM808 and put it in inconsistent state.
Try connecting SIM808 module to PC and use CoolTerm to analyze response after firing AT command.

Arduino SD card fails to write when used with another SPI device

I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).

I2C read from registers with Arduino

I'm having some trouble understanding I2C. This is my first time using the protocol. The documentation says the following
I just don't know if I am supposed to write to a read register and the two bytes are 0x00 and 0x01, or use Wire.request to request two bytes.
I have read registers from 0-20 and several write registers however I'm only interested in the read registers.
Any help would be much appreciated and please ask any questions you might have.
Thanks,
Peter
EDIT
#include <Wire.h>
void setup() {
// put your setup code here, to run once:
Wire.begin();
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
int k = readRegister(0x08, 0x06);
Serial.println(k);
delay(500);
}
uint16_t readRegister(uint8_t i2cAddr, uint8_t regAddr) {
// I2C write sequence to address the given read register
Wire.beginTransmission(i2cAddr); // Module address
Wire.write(regAddr); // Register Address
Wire.write(0); // Command Data = dummy zeroes
Wire.write(0);
Wire.write(regAddr); // Checksum
Wire.endTransmission(); // Finish I2C write sequence
// I2C read sequence to actually get the register value
Wire.requestFrom(i2cAddr, 3);
uint16_t regVal = Wire.read();
regVal <<= 8;
regVal |= Wire.read();
if (Wire.read() == (((regVal >> 8) + regVal) & 0xFF)) {
return regVal; // Checksum OK
}
return 0xFFFF; // Checksum error
}
It seems the only way to say which register you want to read is to complete an I2C write sequence using that register's address. Probably the "Command Data" you use in the write sequence will be irrelevant if you use the address of a read register.
So it would become something like this:
uint16_t readRegister(uint8_t i2cAddr, uint8_t regAddr) {
// I2C write sequence to address the given read register
Wire.beginTransmission(i2cAddr); // Module address
Wire.write(regAddr); // Register Address
Wire.write(0); // Command Data = dummy zeroes
Wire.write(0);
Wire.write(-regAddr); // Checksum
Wire.endTransmission(); // Finish I2C write sequence
// I2C read sequence to actually get the register value
Wire.requestFrom(i2cAddr, 3);
uint16_t regVal = Wire.read();
regVal <<= 8;
regVal |= Wire.read();
if ((Wire.read() + regVal >> 8 + regVal & 0xFF) == 0) {
return regVal; // Checksum OK
}
return 0xFFFF; // Checksum error
}
It is usual in many chips to access subsequent register addresses incrementally by just issuing new read sequences. This way you could do a bulk or multi-byte read. However I'm not sure that's the case here, so you might need to do the write sequence every time.

Resources