rm3100 status register not changing - c++

The rm3100 is working with Arduino Leonardo. I am trying to make it work with esp32.
I am able to write to the registers of an rm3100 and read them. I tried to write to the register and then read its value - it works as expected.
But the measurement registers not changing and the senior bit of the status register (0x34) is always 0. DRDY line stays low.
I tried continuous mode (wrote 0x71 to the register 0x01) and single measurement (wrote 0x70 to the register 0x00).
uint8_t data[1];
write_i2c_register(0x33, 0x8f); // wrote to the test register 0x33
usleep(1000000);
read_i2c_registers(0x33, data, 1);
printf("Test register is %02x\n", data[0]); // printing 0x8f in 0x33 register
write_i2c_register(0x00, 0x70); // initialize single measurement
usleep(1000000);
read_i2c_registers(0x34, data, 1);
printf("Status register is %02x\n", data[0]); // printing 0x00 in 0x34 register
write_i2c_register(0x01, 0x71); // initialize continuous measurement
usleep(1000000);
read_i2c_registers(0x34, data, 1);
printf("Status register is %02x\n", data[0]); // printing 0x00 in 0x34 register
The following points look suspicious:
According to the datasheet https://www.pnicorp.com/wp-content/uploads/RM3100-RM2100-Sensor-Suite-User-Manual-R09-1.pdf – I need to add 0x80 to the register address when reading.
But it doesn’t work in my case – when I add 0x80 – I am getting 0. But when I read without adding – I am getting correct results.
std::vector<int> regs = {0, 1, 4, 5, 6, 7, 8, 9, 11, 36, 37, 38, 39, 40,
41, 42, 43, 44, 51, 52, 53, 54};
for (auto i: regs)
{
read_i2c_registers(i, data, 1); // when I read without adding 0x80
printf("%02x=%02x ", i, data[0]); // I am getting reasonable values
}
printf("\n");
for (auto i: regs)
{
read_i2c_registers(i + 0x80, data, 1); // when I add 0x80 to the reg address
printf("%02x=%02x ", i, data[0]); // I am getting zeros
}
printf("\n");
According to the datasheet – I need to send “stop” when after sending the register address when reading.
It doesn’t work – I am getting timeout error.
void read_i2c_registers(uint8_t reg, uint8_t* data, const uint8_t bytes){
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (I2C_ADDRESS_GEO << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, reg, 1));
// ESP_ERROR_CHECK(i2c_master_stop(cmd)); // <-- timeout when uncommented
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (I2C_ADDRESS_GEO << 1) | I2C_MASTER_READ, 1));
if (bytes > 1)
ESP_ERROR_CHECK(i2c_master_read(cmd, data, bytes - 1, (i2c_ack_type_t) 0));
ESP_ERROR_CHECK(i2c_master_read_byte(cmd, data + bytes - 1, (i2c_ack_type_t) 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
auto err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (err != ESP_OK)
{
std::cout << "err=" << int(err) << "\n";
}
}
void write_i2c_register(const uint8_t reg, const uint8_t data){
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (I2C_ADDRESS_GEO << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, reg, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data, 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
esp_err_t err;
do err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS);
while (err != ESP_OK);
i2c_cmd_link_delete(cmd);
}

As far as I understand read_i2c_registers should call i2c_master_cmd_begin twice (separately for write part and read part).
I adjusted the code and it works now in continuous mode:
void read_i2c_registers(uint8_t reg, uint8_t* data, const uint8_t bytes){
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (I2C_ADDRESS_GEO << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, reg, 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd)); // uncommented
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1/portTICK_PERIOD_MS)); // line added
i2c_cmd_link_delete(cmd); // line added
cmd = i2c_cmd_link_create(); // line added
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (I2C_ADDRESS_GEO << 1) | I2C_MASTER_READ, 1));
if (bytes > 1)
ESP_ERROR_CHECK(i2c_master_read(cmd, data, bytes - 1, (i2c_ack_type_t) 0));
ESP_ERROR_CHECK(i2c_master_read_byte(cmd, data + bytes - 1, (i2c_ack_type_t) 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1/portTICK_PERIOD_MS));
i2c_cmd_link_delete(cmd);
}

Related

MPU6050 stuck in sleepmode (C/C++)/No raw data being transmitted

I have a MPU6050 hooked up to a raspberry pi pico, I am trying to read the data using the i2c protocol. But it only gives 0's, I assume this is due to the fact that its in sleep mode because from what I can tell everything is connected as it should be.
`
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
//mpu address
const static uint8_t MPU_ADDRESS = 0x68;
static void mpu6050_reset() {
// Two byte reset. First byte register, second byte data
// There are a load more options to set up the device in different ways that could be added here
//uint8_t buffer [] = {(uint8_t)65, (uint8_t)66};
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
//printf("b1: %d b2: %d \n", buffer[0], buffer[1]);
uint8_t buf[] = {0x6B, 0x00};
i2c_write_blocking(i2c_default, MPU_ADDRESS, buf, 1, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
}
static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
// For this particular device, we send the device the register we want to read
// first, then subsequently read from the device. The register is auto incrementing
// so we don't need to keep sending the register we want, just the first.
uint8_t buffer[6];
// Start reading acceleration registers from register 0x3B for 6 bytes
uint8_t val = 0x3B;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true); // true to keep master control of bus
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false);
printf("buffer accel, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
for (int i = 0; i < 3; i++) {
accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
}
// Now gyro data from reg 0x43 for 6 bytes
// The register is auto incrementing on each read
val = 0x43;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false); // False - finished with bus
for (int i = 0; i < 3; i++) {
gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
}
printf("buffer gyro, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
val = 0x41;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 2, false); // False - finished with bus
*temp = buffer[0] << 8 | buffer[1];
}
int main() {
//check that pico is powered and running
const uint LED = PICO_DEFAULT_LED_PIN;
gpio_init(LED);
gpio_set_dir(LED, GPIO_OUT);
gpio_put(LED, 1);
//check that pico can use serial output
stdio_init_all();
printf("hello world \n");
//setup i2c buffer address stuff
uint8_t MPU_ACCELRATION_BUFFER = 0x3B;
uint8_t MPU_GRYOSCOPE_BUFFER = 0x43;
//turn on MPU power
const uint MPU_POWER = 1;
gpio_init(MPU_POWER);
gpio_set_dir(MPU_POWER, GPIO_OUT);
gpio_put(MPU_POWER, 1);
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
//while (1){
mpu6050_reset();
//}
int16_t acceleration[3], gyro[3], temp;
while (1) {
mpu6050_reset();
mpu6050_read_raw(acceleration, gyro, &temp);
// These are the raw numbers from the chip, so will need tweaking to be really useful.
// See the datasheet for more information
printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
printf("Temp. = %f\n", (temp / 340.0) + 36.53);
sleep_ms(100);
}
return 0;
}
`
This is the code, using the raspberry pi c/cpp sdk. A large chunk of it is simply the example for the mpu6050 which all seems to be valid, and there is code included meant to wake up the mpu6050. So are there any other methods of waking the MPU6050 up or does the issue appear to be something else within the code?

ESP32 build in Arduino IDE: undefined reference to `CLASS::function' error

I tried to write an Library for the Sensirion SFM3000 Flow Sensor in the Arduino IDE for an ESP32. As long as it was one sketch, everything worked. But as I tried to seperate it into an .h and .cpp file and implemented it as a class, I get some weird error when I try to compile the sketch.
sketch\SFM3019_HSKA.cpp.o:(.literal._ZN12SFM3019_HSKA17i2c_read_flow_CRCEv+0x4): undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
sketch\SFM3019_HSKA.cpp.o: In function `SFM3019_HSKA::i2c_read_flow_CRC()':
sketch/SFM3019_HSKA.cpp:124: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
sketch/SFM3019_HSKA.cpp:128: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
collect2.exe: error: ld returned 1 exit status
exit status 1
Fehler beim Kompilieren für das Board ESP32 Dev Module.
As I understand the error message, it occurs when the i2c_read_flow_CRC() meethod is calling the crc8() method in the last thrid of SFM3019_HSKA.cpp file. By now I don´t see an error in the syntax. But I have also no other idea on how to continue debugging...
This is the main code im trying to use the library in:
#include "SFM3019_HSKA.h"
#include <Wire.h>
SFM3019_HSKA::SensVal_s SensVal = {0, 0, 0};
SFM3019_HSKA SFM3019(0x2E); //Generate Object SFM3019 of class SFM3019_HSKA
void setup() {
// put your setup code here, to run once:
Serial.begin (115200);
delay(100);
Wire.begin (21, 22); // for ESP32: SDA= GPIO_21 /SCL= GPIO_22
SFM3019.i2c_device_check(); //checks if I2C device is available
SFM3019.i2c_write(0x3608); //write 2Byte to start continuous measurement
delay(100);
}
void loop() {
// put your main code here, to run repeatedly:
SensVal.flow = SFM3019.i2c_read_flow_CRC(); //read only Flow Bytes
Serial.println(SensVal.flow, 10);
delay(100);
SensVal = SFM3019.i2c_read_all(); //read all Sensor Bytes
Serial.print("Flow: ");
if (SensVal.flow >= 0) Serial.print(" "); //just for beauty reasons
Serial.print(SensVal.flow,10);
Serial.print(" Temp: ");
Serial.print(SensVal.temp,3);
Serial.print(" Statusword: ");
Serial.print(SensVal.statusword, HEX);
delay(400);
Serial.println();
}
and those are the library files:
SFM3019_HSKA.h
#ifndef SFM3019_HSKA_H // include guard
#define SFM3019_HSKA_H
#include "Arduino.h"
class SFM3019_HSKA {
public: //can be accessed public
SFM3019_HSKA(uint8_t i2cAddress); //Constructor
//may be nicer in private if it works anyway
typedef struct {float flow; float temp; int16_t statusword;} SensVal_s; //Struct for complete Sensor Readout
SensVal_s SensVal = {0, 0, 0}; //initialize with 0
int8_t i2c_device_check(); //function for Initialisation
int8_t i2c_write(const uint16_t SendData); //function to write 16Bit Data to sensor
SensVal_s i2c_read_all(); //function to read Flow, Temperature and Statusword
float i2c_read_flow(); //function to only read Flow
float i2c_read_flow_CRC(); //function to only read Flow with CRC check
private: //can only be accessed by functions oh same object
uint8_t SFM3019addr = 46; //SFM3019 I2C Adress: 46 / 0x2E
uint8_t crc8(const uint8_t data, uint8_t crc); //fuction for CRC confirmation
};
#endif
and the C++ file leading to the error:
SFM3019_HSKA.cpp:
#include "SFM3019_HSKA.h" //when placed in same folder
//#include <SFM3019_HSKA.h> //when placed in standard library folder
#include <Wire.h>
// some values needed for calculation of physical flow and temperature values
#define SFM3019Offset 24576
#define SFM3019ScaleFactorFlow 170.0 //needs to be a float, otherwise it will not calculate in float
#define SFM3019ScaleFactorTemp 200.0 //needs to be a float, otherwise it will not calculate in float
SFM3019_HSKA::SFM3019_HSKA(uint8_t i2cAddress) //constructor
{
//: mI2cAddress(i2cAddress)
SFM3019addr = i2cAddress;
}
/* checks if a Device at the desired address is responding with an ACK */
int8_t SFM3019_HSKA::i2c_device_check(){
Wire.beginTransmission(SFM3019addr); // Begin I2C transmission Address (i)
if (Wire.endTransmission() == 0) // Receive 0 = success (ACK response)
{
Serial.print ("Found Seosor at address");
Serial.print (SFM3019addr, DEC);
Serial.print (" (0x");
Serial.print (SFM3019addr, HEX); // 7 bit address
Serial.println (")");
return 0; //0=device sent ACK
}else{
Serial.print ("Did not receive Acknowledge from I2C address ");
Serial.print (SFM3019addr, DEC);
Serial.print (" (0x");
Serial.print (SFM3019addr, HEX); // 7 bit address
Serial.println (")");
return 1; //no ACK received
}
}
/* writes a 16bit "SendData" to I2C Bus Device "address" */
int8_t SFM3019_HSKA::i2c_write(const uint16_t SendData) {
Wire.beginTransmission(SFM3019addr);
//fill I2C outbuffer
Wire.write((SendData>>8)& 0xFF); //isolate HighByte
Wire.write(SendData & 0xFF); //isolate LowByte
//send I2C outbuffer
Wire.endTransmission();
return 0;
}
/* reads all 9 measurement bytes for flow, temp and status */
SFM3019_HSKA::SensVal_s SFM3019_HSKA::i2c_read_all(){
SensVal_s SensVal = {0}; //create empty struct
Wire.requestFrom(SFM3019addr, 9, true); // Request 9byte (3x16bit + CRC) from the sensor
//while(Wire.available()<3){}; //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
//get Flow Bytes
int16_t flow = Wire.read()<<8; //get Highbyte and shift 8bit to 8MSB
flow = flow | Wire.read(); //get Lowbyte 8LSB
byte CRCflow = Wire.read(); //get CRC Check Byte (you could do a data validy check with that)
//Serial.println(flow, HEX); //raw values for debugging
SensVal.flow = (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions
//get Temperature Bytes
int16_t temp = Wire.read()<<8; //get Highbyte and shift 8bit to 8MSB
temp = temp | Wire.read(); //get Lowbyte 8LSB
byte CRCtemp = Wire.read(); //get CRC Check Byte (you could do a data validy check with that)
//Serial.println(temp, HEX); //raw values for debugging
SensVal.temp = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions
//get StatusWord Bytes
int16_t stat = Wire.read()<<8; //get Highbyte and shift 8bit to 8MSB
stat = stat | Wire.read(); //get Lowbyte 8LSB
byte CRCstat = Wire.read(); //get CRC Check Byte (you could do a data validy check with that)
//Serial.println(stat, HEX); //raw values for debugging
SensVal.statusword = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions
//return all data
return SensVal;
}
/* reads only first 3 bytes for flow and does NO CRC!*/
float SFM3019_HSKA::i2c_read_flow(){
Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
//while(Wire.available()<3){}; //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
int16_t flow = Wire.read()<<8; //get Highbyte and shift 8bit to 8MSB
flow = flow | Wire.read(); //get Lowbyte 8LSB
byte CRC = Wire.read(); //get CRC Check Byte (you could do a data validy check with that)
//Serial.println(flow, HEX); //raw values for debugging
return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions
}
/* reads only first 3 bytes for flow and DOES CRC*/
float SFM3019_HSKA::i2c_read_flow_CRC(){
Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
//while(Wire.available()<3){}; //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
uint8_t Highbyte = Wire.read(); //get Highbyte 8MSB
uint8_t Lowbyte = Wire.read(); //get Lowbyte 8LSB
uint8_t CRC = Wire.read(); //get CRC Check Byte
//Confirm CRC
uint8_t mycrc = 0xFF; // initialize crc variable
mycrc = crc8(Highbyte, mycrc); // let first byte through CRC calculation
mycrc = crc8(Lowbyte, mycrc); // and the second byte too
if (mycrc != CRC) { // check if the calculated and the received CRC byte matches
//Serial.println("Error: wrong CRC");
return -10000; //extreme low value, so user knows somethig is wrong
} else {
//Serial.println("Success: identical CRC");
int16_t flow = (Highbyte<<8) | Lowbyte; //stack the to bytes together as signed int16
return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions
}
}
/* calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t crc8(const uint8_t data, uint8_t crc)
{
crc ^= data; //crc XOR data
for ( uint8_t i = 8; i; --i ) {
crc = ( crc & 0x80 )
? (crc << 1) ^ 0x31
: (crc << 1);
}
return crc;
}
I would be really thankfull for any idea on how to continue...
/* calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t crc8(const uint8_t data, uint8_t crc)
{
crc ^= data; //crc XOR data
for ( uint8_t i = 8; i; --i ) {
crc = ( crc & 0x80 )
? (crc << 1) ^ 0x31
: (crc << 1);
}
return crc;
}
Needs to be:
/* calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t SFM3019_HSKA::crc8(const uint8_t data, uint8_t crc)
{
crc ^= data; //crc XOR data
for ( uint8_t i = 8; i; --i ) {
crc = ( crc & 0x80 )
? (crc << 1) ^ 0x31
: (crc << 1);
}
return crc;
}
You just forgot to mark the defined method as part of the class. Simple typo error.

serial read changes input & doesn't read whole line

Large strings sent over serial are not correctly read using an Arduino Uno and the Arduino IDE. When the typed command is too long, not the whole data is returned and sometimes is is even random numbers.
99,3,0,1,0,0,0 Results correctly in (not sure why there is an ending , tho):
receivedValues are: 99,3,0,1,0,0,0,
99,3,0,0,0,0,0 Results correctly in: receivedValues are: 99,3,0,0,0,0,0,
Where is starts to go wrong:
99,3,0,100,200,300,400 Results in: receivedValues are: 99,3,0,100,200,44,144,
99,123456789 Results in: receivedValues are: 99,21,0,1,200,200,244,
99,3,0,1,200,200,2000 Results in: receivedValues are: 99,3,0,1,200,200,208,
Here is the part of my code that is relevant:
uint8_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
#define HEADER 0 // 99
#define CMD 1 // LICHT (2) || GEUR (3)
#define DATA0 2 // KLEUR INDEX || GEUR INDEX
#define DATA1 3 // H || ON / OFF
#define DATA2 4 // S
#define DATA3 5 // V
#define DATA4 6 // BlendTime
#define CHECK 99
#define ON 1
#define OFF 0
bool messageReceived = false;
bool startBlending = false;
void setup()
{
Serial.begin(9600);
}
void loop()
{
ParseSerial();
if (messageReceived)
{
printMessage();
// CheckCommand();
messageReceived = false;
}
}
void ParseSerial()
{
int serialIndex = 0;
if (Serial.available() > 8)
{
while (0 < Serial.available())
{
String bufferString;
int bufferInt;
bufferString = Serial.readStringUntil(',');
bufferInt = bufferString.toInt();
receivedValues[serialIndex] = bufferInt;
serialIndex++;
}
if (receivedValues[HEADER] == CHECK)
{
Serial.print("receivedValues[0]: ");
Serial.println(receivedValues[0]);
messageReceived = true;
}
if (receivedValues[HEADER] != CHECK)
{
Serial.println("not a good package");
}
Serial.flush();
}
else
{
Serial.flush();
}
}
void printMessage()
{
Serial.print("receivedValues are: ");
for (int i = 0; i < 7; i++)
{
Serial.print(receivedValues[i]);
Serial.print(",");
}
Serial.println();
}
If the header of the message does not start with 99 it will write not a good package. What is noticeable it that when I do enter a command with 99 at the beginning ONCE, it will write not a good package twice most of the time.
receivedValues is declared as uint8_t receivedValues[7]. The maximum value for uint8_t is 255. If you try to store a larger number, it will be truncated.
If you want to store larger numbers, you need to pick a wider integer type for your array, e.g.
uint32_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
Which will work up to UINT32_MAX, which is 0xFFFFFFFF (4294967295)
I found the solution to this problem. Changing uint8_t was not the answer.
A byte of 8 binary bits can represent 28 = 256 numbers: 0 - 255. The
serial connection sends data byte by byte, so if you want to send a
number larger than 255, you'll have to send multiple bytes
Link to source:
https://forum.arduino.cc/index.php?topic=492055.0
I ended up sending a smaller number (minutes) than 255, and then in the Arduino code multiply it again (to seconds).

RtAudio - Playing samples from wav file

I am currently trying to learn audio programming. My goal is to open a wav file, extract everything and play the samples with RtAudio.
I made a WaveLoader class which let's me extract the samples and meta data. I used this guide to do that and I checked that everything is correct with 010 editor. Here is a snapshot of 010 editor showing the structure and data.
And this is how i store the raw samples inside WaveLoader class:
data = new short[wave_data.payloadSize]; // - Allocates memory size of chunk size
if (!fread(data, 1, wave_data.payloadSize, sound_file))
{
throw ("Could not read wav data");
}
If i print out each sample I get : 1, -3, 4, -5 ... which seems ok.
The problem is that I am not sure how I can play them. This is what I've done:
/*
* Using PortAudio to play samples
*/
bool Player::Play()
{
ShowDevices();
rt.showWarnings(true);
RtAudio::StreamParameters oParameters; //, iParameters;
oParameters.deviceId = rt.getDefaultOutputDevice();
oParameters.firstChannel = 0;
oParameters.nChannels = mAudio.channels;
//iParameters.deviceId = rt.getDefaultInputDevice();
//iParameters.nChannels = 2;
unsigned int sampleRate = mAudio.sampleRate;
// Use a buffer of 512, we need to feed callback with 512 bytes everytime!
unsigned int nBufferFrames = 512;
RtAudio::StreamOptions options;
options.flags = RTAUDIO_SCHEDULE_REALTIME;
options.flags = RTAUDIO_NONINTERLEAVED;
//&parameters, NULL, RTAUDIO_FLOAT64,sampleRate, &bufferFrames, &mCallback, (void *)&rawData
try {
rt.openStream(&oParameters, NULL, RTAUDIO_SINT16, sampleRate, &nBufferFrames, &mCallback, (void*) &mAudio);
rt.startStream();
}
catch (RtAudioError& e) {
std::cout << e.getMessage() << std::endl;
return false;
}
return true;
}
/*
* RtAudio Callback
*
*/
int mCallback(void * outputBuffer, void * inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void * userData)
{
unsigned int i = 0;
short *out = static_cast<short*>(outputBuffer);
auto *data = static_cast<Player::AUDIO_DATA*>(userData);
// if i is more than our data size, we are done!
if (i > data->dataSize) return 1;
// First time callback is called data->ptr is 0, this means that the offset is 0
// Second time data->ptr is 1, this means offset = nBufferFrames (512) * 1 = 512
unsigned int offset = nBufferFrames * data->ptr++;
printf("Offset: %i\n", offset);
// First time callback is called offset is 0, we are starting from 0 and looping nBufferFrames (512) times, this gives us 512 bytes
// Second time, the offset is 1, we are starting from 512 bytes and looping to 512 + 512 = 1024
for (i = offset; i < offset + nBufferFrames; ++i)
{
short sample = data->rawData[i]; // Get raw sample from our struct
*out++ = sample; // Pass to output buffer for playback
printf("Current sample value: %i\n", sample); // this is showing 1, -3, 4, -5 check 010 editor
}
printf("Current time: %f\n", streamTime);
return 0;
}
Inside callback function, when I print out sample values I get exactly like 010 editor? Why isnt rtaudio playing them. What is wrong here? Do I need to normalize sample values to between -1 and 1?
Edit:
The wav file I am trying to play:
Chunksize: 16
Format: 1
Channel: 1
SampleRate: 48000
ByteRate: 96000
BlockAlign: 2
BitPerSample: 16
Size of raw samples total: 2217044 bytes
For some reason it works when I pass input parameters to the openStream()
RtAudio::StreamParameters oParameters, iParameters;
oParameters.deviceId = rt.getDefaultOutputDevice();
oParameters.firstChannel = 0;
//oParameters.nChannels = mAudio.channels;
oParameters.nChannels = mAudio.channels;
iParameters.deviceId = rt.getDefaultInputDevice();
iParameters.nChannels = 1;
unsigned int sampleRate = mAudio.sampleRate;
// Use a buffer of 512, we need to feed callback with 512 bytes everytime!
unsigned int nBufferFrames = 512;
RtAudio::StreamOptions options;
options.flags = RTAUDIO_SCHEDULE_REALTIME;
options.flags = RTAUDIO_NONINTERLEAVED;
//&parameters, NULL, RTAUDIO_FLOAT64,sampleRate, &bufferFrames, &mCallback, (void *)&rawData
try {
rt.openStream(&oParameters, &iParameters, RTAUDIO_SINT16, sampleRate, &nBufferFrames, &mCallback, (void*) &mAudio);
rt.startStream();
}
catch (RtAudioError& e) {
std::cout << e.getMessage() << std::endl;
return false;
}
return true;
It was so random when I was trying to playback my mic. I left input parameters and my wav file was suddenly playing. Is this is a bug?

getting results from controller via usb failes

Im trying to write a programm in c++ to let my computer communicate with a trinamic steprockerboard.
They already provided an example file, to get you on the way. This works perfect, but is really simplistic.
Now I want to read the results from the usb device, and they made a function for that:
//Read the result that is returned by the module
//Parameters: Handle: handle of the serial port, as returned by OpenRS232
//Address: pointer to variable to hold the reply address returned by the module
// Status: pointer to variable to hold the status returned by the module (100 means okay)
//Value: pointer to variable to hold the value returned by the module
prototype:
UCHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
Now I wrote the following:
UCHAR* adr;
UCHAR* stat;
int* val;
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -3200); // move to next position
SendCmd(RS232Handle,1, TMCL_GAP, 8, 0, 0); // tell motor to look if position is reached
GetResult(RS232Handle,adr,stat,val); //ask for the result, value must give a 1 if so
printf("results from USB device: adr=%d, stat=%d, val=%d\n", adr, stat, val);
But when I run the program, and try this option, the program chrashes.
Has anybody got an idea what might cause the problem? (the code I supplied is only a part of my program, the whole code can be find below.
It is not my intention that you read the whole code, the problem should be above, but only for who is interested I also put the rest down here)
// TMCLTest.cpp : Show how to communicate with a TMCM module in TMCL
//
#include "stdafx.h"
#include <iostream>
//Opcodes of all TMCL commands that can be used in direct mode
#define TMCL_ROR 1
#define TMCL_ROL 2
#define TMCL_MST 3
#define TMCL_MVP 4
#define TMCL_SAP 5
#define TMCL_GAP 6
#define TMCL_STAP 7
enter code here#define TMCL_RSAP 8
enter code here#define TMCL_SGP 9
#define TMCL_GGP 10
#define TMCL_STGP 11
#define TMCL_RSGP 12
#define TMCL_RFS 13
#define TMCL_SIO 14
#define TMCL_GIO 15
#define TMCL_SCO 30
#define TMCL_GCO 31
#define TMCL_CCO 32
//Opcodes of TMCL control functions (to be used to run or abort a TMCL program in the module)
#define TMCL_APPL_STOP 128
#define TMCL_APPL_RUN 129
#define TMCL_APPL_RESET 131
//Options for MVP commandds
#define MVP_ABS 0
#define MVP_REL 1
#define MVP_COORD 2
//Options for RFS command
#define RFS_START 0
#define RFS_STOP 1
#define RFS_STATUS 2
#define FALSE 0
#define TRUE 1
//Result codes for GetResult
#define TMCL_RESULT_OK 0
#define TMCL_RESULT_NOT_READY 1
#define TMCL_RESULT_CHECKSUM_ERROR 2
//Open serial interface
//Usage: ComHandle=OpenRS232("COM1", CBR_9600)
HANDLE OpenRS232(const char* ComName, DWORD BaudRate)
{
HANDLE ComHandle;
DCB CommDCB;
COMMTIMEOUTS CommTimeouts;
ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(GetLastError()!=ERROR_SUCCESS) return INVALID_HANDLE_VALUE;
else
{
GetCommState(ComHandle, &CommDCB);
CommDCB.BaudRate=BaudRate;
CommDCB.Parity=NOPARITY;
CommDCB.StopBits=ONESTOPBIT;
CommDCB.ByteSize=8;
CommDCB.fBinary=1; //Binary Mode only
CommDCB.fParity=0;
CommDCB.fOutxCtsFlow=0;
CommDCB.fOutxDsrFlow=0;
CommDCB.fDtrControl=0;
CommDCB.fDsrSensitivity=0;
CommDCB.fTXContinueOnXoff=0;
CommDCB.fOutX=0;
CommDCB.fInX=0;
CommDCB.fErrorChar=0;
CommDCB.fNull=0;
CommDCB.fRtsControl=RTS_CONTROL_TOGGLE;
CommDCB.fAbortOnError=0;
SetCommState(ComHandle, &CommDCB);
//Set buffer size
SetupComm(ComHandle, 100, 100);
//Set up timeout values (very important, as otherwise the program will be very slow)
GetCommTimeouts(ComHandle, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout=MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier=0;
CommTimeouts.ReadTotalTimeoutConstant=0;
SetCommTimeouts(ComHandle, &CommTimeouts);
return ComHandle;
}
}
//Close the serial port
//Usage: CloseRS232(ComHandle);
void CloseRS232(HANDLE Handle)
{
CloseHandle(Handle);
}
//Send a binary TMCL command
//e.g. SendCmd(ComHandle, 1, TMCL_MVP, MVP_ABS, 1, 50000); will be MVP ABS, 1, 50000 for module with address 1
//Parameters: Handle: Handle of the serial port (returned by OpenRS232).
// Address: address of the module (factory default is 1).
// Command: the TMCL command (see the constants at the begiining of this file)
// Type: the "Type" parameter of the TMCL command (set to 0 if unused)
// Motor: the motor number (set to 0 if unused)
// Value: the "Value" parameter (depending on the command, set to 0 if unused)
void SendCmd(HANDLE Handle, UCHAR Address, UCHAR Command, UCHAR Type, UCHAR Motor, INT Value)
{
UCHAR TxBuffer[9];
DWORD BytesWritten;
int i;
TxBuffer[0]=Address;
TxBuffer[1]=Command;
TxBuffer[2]=Type;
TxBuffer[3]=Motor;
TxBuffer[4]=Value >> 24;
TxBuffer[5]=Value >> 16;
TxBuffer[6]=Value >> 8;
TxBuffer[7]=Value & 0xff;
TxBuffer[8]=0;
for(i=0; i<8; i++)
TxBuffer[8]+=TxBuffer[i];
//Send the datagram
WriteFile(Handle, TxBuffer, 9, &BytesWritten, NULL);
}
//Read the result that is returned by the module
//Parameters: Handle: handle of the serial port, as returned by OpenRS232
// Address: pointer to variable to hold the reply address returned by the module
// Status: pointer to variable to hold the status returned by the module (100 means okay)
// Value: pointer to variable to hold the value returned by the module
//Return value: TMCL_RESULT_OK: result has been read without errors
// TMCL_RESULT_NOT_READY: not enough bytes read so far (try again)
// TMCL_RESULT_CHECKSUM_ERROR: checksum of reply packet wrong
UCHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
{
UCHAR RxBuffer[9], Checksum;
DWORD Errors, BytesRead;
COMSTAT ComStat;
int i;
//Check if enough bytes can be read
ClearCommError(Handle, &Errors, &ComStat);
if(ComStat.cbInQue>8)
{
//Receive
ReadFile(Handle, RxBuffer, 9, &BytesRead, NULL);
Checksum=0;
for(i=0; i<8; i++)
Checksum+=RxBuffer[i];
if(Checksum!=RxBuffer[8]) return TMCL_RESULT_CHECKSUM_ERROR;
*Address=RxBuffer[0];
*Status=RxBuffer[2];
*Value=(RxBuffer[4] << 24) | (RxBuffer[5] << 16) | (RxBuffer[6] << 8) | RxBuffer[7];
} else return TMCL_RESULT_NOT_READY;
return TMCL_RESULT_OK;
}
int main(int argc, char* argv[])
{
int i;
int Type, Motor, Velocity, Position,ref1;
UCHAR Address, Status;
int Value, Timeout;
HANDLE RS232Handle;
RS232Handle=OpenRS232("COM3", 9600);
// set parameters
SendCmd(RS232Handle, 1, TMCL_SAP, 140, 0, 5); //SAP 140, 0, 5 // set microsteps to 32 (32 additional steps per step of 1.8 degr.)
//SAP 4, 0, 500 //set max vel.
//SAP 5, 0, 100 //set max acc.
//SAP 6, 0, 255 //set abs. max current to 2.8 ampere
//SAP 7, 0, 50 //set standby current ((50/250)*2.8A)
printf("VPI Test Setup\n \n" );
do
{
printf("1 - Rotate clockwise (10 rotations)\n");
printf("2 - Rotate counter-clockwise (10 rotations)\n");
printf("3 - Stop motor\n");
printf("4 - Start test (First 100 rotations clockwise, \n then 100 rotations counter clockwise)\n");
printf("\n99 - End\n");
scanf("%d", &i);
switch(i)
{
case 1:
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, 32000); //ABS(4th parameter) = 0
break;
case 2:
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -32000); //ABS(4th parameter) = 0
break;
case 3:
SendCmd(RS232Handle, 1, TMCL_MST, 0, 0, 0);
break;
case 4:
//SendCmd(RS232Handle, 1, TMCL_RFS,0,0,0);
printf("Test started \n" );
//UCHAR done;
UCHAR* adr;
UCHAR* stat;
int* val;
//SendCmd(RS232Handle, 1, TMCL_SAP, 193, 1, 2); //SAP 193,1,2
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -3200); //ABS(4th parameter) = 0
SendCmd(RS232Handle,1, TMCL_GAP, 8, 0, 0);
GetResult(RS232Handle,adr,stat,val);
printf("results from USB device: adr=%d, stat=%d, val=%d\n", adr, stat, val);
//CHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
// if(done != 2)
// {
// printf("rotation backwards started \n");
// SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, 3200);
// }
// }
break;
}
SendCmd(RS232Handle, 1, TMCL_ROL, 0, Motor, Velocity);
SendCmd(RS232Handle, 1, TMCL_ROL, 0, Motor, Velocity);
if(i==1 || i==2 || i==3 || i==4)
{
Address=0;
Status=0;
Value=0;
Timeout=GetTickCount();
while(GetResult(RS232Handle, &Address, &Status, &Value) ==TMCL_RESULT_NOT_READY && abs(GetTickCount()-Timeout)<1000);
printf("Result: Address=%d, Status=%d, Value=%d\n", Address, Status, Value);
}
}
while(i!=99);
CloseRS232(RS232Handle);
return 0;
}
Address, Status and Value should point to valid variables. So, your code should look something like:
UCHAR adr;
UCHAR stat;
int val;
GetResult(RS232Handle,&adr,&stat,&val);
What is happening now is that your variables (adr, stat and val) are not initialized, so, they point to random locations in memory. When you pass these variables to GetResult, it tries to write to those random locations.