I've been getting a few crc errors transferring data between the pi and teensy since moving the teensy to a smaller breadboard.. (could be totally unrelated and need blocking code etc) but it generally occurs when a servo pulses.
I've got a class that moves a servo every minute to simulate the sun moving through the day..
The teensy is also getting data from a pi via serial.
I've implemented CRC32 and ever since introducing the sun class I've been seeing errors in data transfer usually occuring around the same point. I have lowered the baud and increased the data transfer timeout but it is still getting errors.
Just wondering if anyone could suggest any more solutions.
Please see source (please forgive me there's some pretty dirty code in there)
The main areas are setpulselengthandrotate and the Update function:
The output from the serial monitor is
Packet data length is 155
CRC32 Check Error!
{"weatherinfo": {"moonrise": "6:49:00", "moonset": "19:12:00", "temp_c": 24.2, "weather": "cloudy lightningra",set ":00 "t "/01 "rrme :000 eciti: ",sis: :0
as you can see the json is getting cut off
--SUN--
Relevant Parts of the Teensy Code
Thanks for your time,
Sorry for the code dump.
Tom
I've got a class that moves a servo every minute to simulate the sun moving through the day..
The teensy is also getting data from a pi via serial.
I've implemented CRC32 and ever since introducing the sun class I've been seeing errors in data transfer usually occuring around the same point. I have lowered the baud and increased the data transfer timeout but it is still getting errors.
Just wondering if anyone could suggest any more solutions.
Please see source (please forgive me there's some pretty dirty code in there)
The main areas are setpulselengthandrotate and the Update function:
The output from the serial monitor is
Packet data length is 155
CRC32 Check Error!
{"weatherinfo": {"moonrise": "6:49:00", "moonset": "19:12:00", "temp_c": 24.2, "weather": "cloudy lightningra",set ":00 "t "/01 "rrme :000 eciti: ",sis: :0
as you can see the json is getting cut off
--SUN--
Code:
// Sun.h
#ifndef Sun_H
#define Sun_H
////#include <Arduino.h>
#include <FastLED.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <TimeLib.h>
#include <string.h>
class Sun
{
private:
void SetPulseLenAndRotate(float degreeToRotateTo);
Adafruit_PWMServoDriver pwm;
void UpdateSunLEDColour();
void Setup();
public:
Sun();
void Initialise(Adafruit_PWMServoDriver pwmDriver,time_t sunrise,time_t sunset,time_t currentDate);
void Update();
void Reset(time_t sunrise,time_t sunset);
bool IsInitialised();
};
#endif
Code:
//Sun.cpp
//Date time from string function sourced here http://stackoverflow.com/questions/32523230/how-convert-string-to-datetime-c
//Fast LED initialisation checked from here: http://hybrid.chadmeby.com/2016/10/25/simple-fastled-analog-input-to-hue/
#include <Arduino.h>
#include "Sun.h"
#include <TimeLib.h>
#include <time.h>
#define PWM_LOCATION 0
#define DATA_PIN 21
#define NUM_LEDS 1
#define CHIPSET WS2811 //led chipset (neopixels)
#define COLOR_ORDER GRB
#define BRIGHTNESS 200
#define SERVOMIN 150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 600 // this is the 'maximum' pulse length count (out of 4096)
#define SUN_START_ANGLE 15.0
#define SUN_END_ANGLE 165.0
static CRGB leds[NUM_LEDS];
const double hslSaturation = 100.0;
const double hslLightness = 50.0;
static float numMinsSinceSunrise;
static float minutesBetweenSunriseSunset;
static time_t sunriseDateTime;
static time_t sunsetDateTime;
float degreesPerMinute;
boolean isInitialised;
const unsigned long interval = 60000; // update every 1 min as milliseconds
static unsigned long lastUpdate; // last update of storm cycle
typedef struct {
double h;
double s;
double l;
} HSL;
HSL coloursOfTheDay [9] = {{30.0, hslSaturation, hslLightness}, {31.0, hslSaturation, hslLightness}, {33.0, hslSaturation, hslLightness}, {33.0, hslSaturation, hslLightness}, {60.0, hslSaturation, hslLightness}, {1.0, hslSaturation, hslLightness}, {212.0, hslSaturation, hslLightness}, {31.0, hslSaturation, hslLightness}, {30.0, hslSaturation, hslLightness}};
double previousColourHue = 0;
int count = 0;
double currentColourFromBand[3];
int previousColourOfTheDayBand = 0;
int minsInColourBand = 0;
static int colourOfTheDayBand = 0;
static time_t currentDate;
double lerp(double a, double b, double f)
{
return a + f * (b - a);
}
Sun::Sun()
{
}
void Sun::Initialise(Adafruit_PWMServoDriver pwmDriver,time_t sunrise,time_t sunset,time_t newDate) {
currentDate = newDate;
FastLED.setMaxPowerInVoltsAndMilliamps(3.3,500);
FastLED.addLeds<CHIPSET, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050); //magic happens here
FastLED.setBrightness(BRIGHTNESS);
pwm = pwmDriver;
sunriseDateTime = sunrise;
sunsetDateTime = sunset;
Setup();
}
void Sun::Setup() {
SetPulseLenAndRotate(SUN_START_ANGLE);
previousColourHue = currentColourFromBand[0];
previousColourOfTheDayBand = 0;
// Actually, it is same, what do you think about it?
minutesBetweenSunriseSunset = (sunsetDateTime - sunriseDateTime) / 60;
degreesPerMinute = (SUN_END_ANGLE - SUN_START_ANGLE) / minutesBetweenSunriseSunset;
isInitialised = true;
}
bool Sun::IsInitialised() {
return isInitialised;
}
void Sun::Reset(time_t sunrise,time_t sunset) {
sunriseDateTime = sunrise;
sunsetDateTime = sunset;
Setup();
}
void Sun::SetPulseLenAndRotate(float degreeToRotateTo) {
int pulselen = map(degreeToRotateTo, SUN_START_ANGLE, SUN_END_ANGLE, SERVOMIN, SERVOMAX);
for(uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm.setPWM(PWM_LOCATION, 0, pulselen);
}
delay(500); //Give the servo time to get there;
}
void Sun::UpdateSunLEDColour() {
Serial.println("mins since sunrise");
Serial.println(numMinsSinceSunrise);
float numMinsInEachColourBand = minutesBetweenSunriseSunset / sizeof(coloursOfTheDay);
Serial.println("num mins in each colour band");
Serial.println(numMinsInEachColourBand);
//Get the number of minutes inside each colour band so we can use it to calculate the steps we're on
Serial.println("Previous Colour of the day band");
Serial.println(previousColourOfTheDayBand);
Serial.println("Color of the day band");
Serial.println(colourOfTheDayBand);
Serial.println("mins in colour band");
Serial.println(minsInColourBand);
Serial.println("Current colour index");
Serial.println(colourOfTheDayBand);
currentColourFromBand[0] = coloursOfTheDay[colourOfTheDayBand].h;
currentColourFromBand[1] = coloursOfTheDay[colourOfTheDayBand].s;
currentColourFromBand[2] = coloursOfTheDay[colourOfTheDayBand].l;
Serial.println("CURRENT COLOUR FROM BAND");
Serial.println(currentColourFromBand[0]);
int nextColourOfTheDayBand = min(colourOfTheDayBand + 1, sizeof(coloursOfTheDay));
Serial.println(nextColourOfTheDayBand);
Serial.println("NEXT COLOUR FROM DAY BAND H");
Serial.println(coloursOfTheDay[nextColourOfTheDayBand].h);
double nextColourFromBand[3] = { coloursOfTheDay[nextColourOfTheDayBand].h, coloursOfTheDay[nextColourOfTheDayBand].s, coloursOfTheDay[nextColourOfTheDayBand].l};
//Where are we in our current colour range for lerp-ing
float stepIncrement = minsInColourBand / numMinsInEachColourBand;
double nextColourHueLerped = lerp(previousColourHue, nextColourFromBand[0], stepIncrement);
Serial.println("Next colour hue lerped");
Serial.println(nextColourHueLerped);
Serial.println("Previous Colour Hue Lerped");
Serial.println(previousColourHue);
Serial.println("current colour from band hsl");
Serial.println(currentColourFromBand[0]);
int distance = (int)nextColourHueLerped - previousColourHue;
if (distance < 0)
{
distance = distance + 360;
}
double hueStepValue = 0.0;
Serial.println("distance");
Serial.println(distance);
for (int i = 0; i < distance; i = i + 2)
{
hueStepValue = previousColourHue + i;
if (hueStepValue > 359)
{
hueStepValue = hueStepValue - 360;
}
if (hueStepValue < 0)
{
hueStepValue = hueStepValue + 360;
}
Serial.print("Hue Step Value");
Serial.print(hueStepValue);
leds[0] = CHSV(hueStepValue, hslSaturation, hslLightness);
FastLED.show();
previousColourHue = hueStepValue;
}
previousColourHue = (int)nextColourHueLerped;
minsInColourBand++;
numMinsSinceSunrise++;
if(minsInColourBand >= numMinsInEachColourBand) {
Serial.println("colour of the DOES NOT match previous");
previousColourOfTheDayBand = colourOfTheDayBand;
colourOfTheDayBand++;
colourOfTheDayBand = min(colourOfTheDayBand,11);
minsInColourBand = 0;
}
}
void Sun::Update() {
unsigned long currentMillis = millis();
if(now() < sunsetDateTime && now() > sunriseDateTime) {
unsigned long secondsSinceCurrentTimeAndSunrise = sunsetDateTime - sunriseDateTime;
if(numMinsSinceSunrise < minutesBetweenSunriseSunset) {
if(currentMillis - lastUpdate > interval) {
lastUpdate = millis();
float angleToRotateTo = numMinsSinceSunrise * degreesPerMinute;
SetPulseLenAndRotate(angleToRotateTo);
UpdateSunLEDColour();
numMinsSinceSunrise++;
}
}
} else {
leds[0] = CHSV(0,0,0);
FastLED.show();
}
}
Relevant Parts of the Teensy Code
Code:
// CRC32
#include <FastCRC.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
#define MAX_BUFFLEN 1024
FastCRC32 CRC32;
static uint16_t dataBufferIndex = 0;
static char Buff[MAX_BUFFLEN]; // This is common beffer for Serial communiaction between RPI and teensy.
static uint32_t nTime = millis();
static bool isReceivingData = false;
const uint32_t serialDataTimeout = 500;
Code:
void setup() {
Serial.begin(9600);
while (!Serial && millis() < 2000); // Teensy is fast so we pause here to get a chance to capture all the serial debugging
Serial.println("Start cloud setup");
//pciSetup(2);
// BEGIN SETTING UP STEPPER MOTOR
/*The device starts by setting the home position on a stepper motor using
* a hall effect sensor. When it reaches the bottom of its run and activates the hall effect sensor
* we are ready to begin
*/
weatherCloud.setSpeed(1600);
weatherCloud.Initialise();
//Serial.println("End cloud initialise home");
//END SETTING UP STEPPER MOTOR
//BEGIN SETTING UP USER LOCATIONS
//firstUserLocation.Initialise(pwm, 1,1);
//secondUserLocation.Initialise(pwm, 2,1);
// Serial speed set for Pi to Teensy communication
Serial1.begin(9600);
//Screen doesn't work yet??
tft.begin();
tft.fillScreen(BLACK);
tft.setCursor(0, 5);
tft.setTextColor(RED);
tft.setTextSize(1);
tft.println("Hello World!");
Serial.println("init");
}
Code:
uint8_t ProcessMessage(char* message)
{
StaticJsonBuffer<MAX_BUFFLEN> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(message);
if (root == JsonObject::invalid())
return false;
JsonObject& weather = root["weatherinfo"].asObject();
if(weather != JsonObject::invalid())
{
Serial.println("Weather Json");
// This message is for weather
const char* tempArray = root["weatherinfo"]["temp_c"];
String tempDegreesCelcius = String(tempArray);
//
const char* weatherArray = root["weatherinfo"]["weather"];
String weather = String(weatherArray);
const char* precipitationArray = root["weatherinfo"]["precipitation"];//
String precipitationDescription = String(precipitationArray);
//This would need a lot more fleshing out and better smarts but for the purposes of a demo it's ok
if(weather.length() > 0) {
boolean cloudActive = false;
String weatherLowered = weather.toLowerCase();
if(weatherLowered.indexOf("cloudy") > 0 || weatherLowered.indexOf("clouds") > 0) {
weatherCloud.stepperStatus = FORWARD;
cloudActive = true;
}
if(weatherLowered.indexOf("lightning") > 0) {
weatherCloud.cloudWeatherStatus = LIGHTNING;
if(weatherLowered.indexOf("rain") > 0 || weatherLowered.indexOf("thunderstorm") > 0) {
weatherCloud.cloudWeatherStatus = LIGHTNING_AND_RAIN;
}
cloudActive = true;
}
if(weatherLowered.indexOf("rain") > 0 || weatherLowered.indexOf("showers") > 0 || weatherLowered.indexOf("thunderstorm") > 0) {
weatherCloud.cloudWeatherStatus = RAIN;
}
}
const char* currentTimeArray = root["weatherinfo"]["currtime"];
String currentTime = String(currentTimeArray);
//
Serial.print("Currrent time is ");
Serial.println(currentTime);
timeFromString(currentTimeArray);
const char* sunrise = root["weatherinfo"]["sunrise"];
String strsunrise = String(sunrise);
//
time_t sunriseTime = timeFromString(sunrise);
//Serial.println(sunrise_time);
const char* sunsetArray = root["weatherinfo"]["sunset"];
String sunset = String(sunsetArray);
time_t sunsetTime = timeFromString(sunsetArray);
const char* dateArray = root["weatherinfo"]["date"];
String date = String(dateArray);
time_t dateFromWeather = dateFromString(dateArray);
if(!sun.IsInitialised()) {
currentDate = dateFromWeather;
}
//If we are in to the next day we need to reset the sun
if(day(dateFromWeather) != day(currentDate)) {
Serial.println("Resetting sun to the start");
sun.Reset(sunriseTime, sunsetTime);
currentDate = dateFromWeather;
}
const char* moonriseArray = root["weatherinfo"]["moonrise"];
String moonrise = String(moonriseArray);
//
const char* moonsetArray = root["weatherinfo"]["moonset"];
String moonset = String(moonsetArray);
if(!sun.IsInitialised()) {
sun.Initialise(pwm, sunriseTime, sunsetTime, currentDate);
}
}
else
{
JsonObject& Person = root["person"].asObject();
if(Person != JsonObject::invalid())
{
// User ID
int userID = Person["userID"].as<uint8_t>();
Serial.println(userID);
// User Name
const char* userName = Person["userName"];
String struserName = String(userName);
Serial.println(struserName);
// Location ID
int locationID = Person["locationID"].as<uint8_t>();
Serial.println(locationID);
//please don't judge me.. I know this is horrible :)
switch (userID) {
case 1:
firstUserLocation.RotateToLocation(locationID);
break;
case 2:
secondUserLocation.RotateToLocation(locationID);
break;
break;
}
}
}
void loop() {
// Receing Packet
if(Serial1.available())
{ // If teensy is receiving data,
isReceivingData = true;
nTime = millis();
char ch = Serial1.read();
Buff[dataBufferIndex] = ch;
dataBufferIndex++; //
if(dataBufferIndex >= MAX_BUFFLEN)
dataBufferIndex = 0;
}
if(nTime + serialDataTimeout < millis() && isReceivingData == true)
{
// End Packet
isReceivingData = false;
Serial.print("Packet data length is ");
Serial.println(dataBufferIndex - 4);
uint32_t CRC1st = Buff[dataBufferIndex - 4];
CRC1st <<= 8;
CRC1st += Buff[dataBufferIndex - 3];
CRC1st <<= 8;
CRC1st += Buff[dataBufferIndex - 2];
CRC1st <<= 8;
CRC1st += Buff[dataBufferIndex - 1];
uint32_t CRC2nd = CRC32.crc32((uint8_t*)Buff, dataBufferIndex - 4);
if(CRC1st != CRC2nd)
{
Serial.println("CRC32 Check Error!");
for(uint16_t idx = 0; idx < dataBufferIndex - 4; idx++)
Serial.print((char)Buff[idx]);
Serial.println();
}
else
{
Serial.println("Received message:");
for(uint16_t idx = 0; idx < dataBufferIndex - 4; idx++)
Serial.print((char)Buff[idx]);
Serial.println();
Buff[dataBufferIndex - 4] = '\0';
Buff[dataBufferIndex - 3] = '\0';
Buff[dataBufferIndex - 2] = '\0';
Buff[dataBufferIndex - 1] = '\0';
ProcessMessage(Buff);
}
dataBufferIndex = 0;
}
//if(!isReceivingData) {
weatherCloud.Update();
sun.Update();
//}
}
Thanks for your time,
Sorry for the code dump.
Tom
Last edited: