PLL Voltage scalling STM32 - microcontroller

I am working with the STM32F767 Nucleo board and currently, I trying to set the PLL as the system clock. While I have been able, thanks to an example generated by the CubeMX, I really don't understand why it must be done so. The setup is:
HSI = 16MHz
PLLM = 8
VCO_Input_Frequency = 16/8 = 2MHz
PLLN = 144
Frequency = 144*2 = 288MHz
PLLP = 6
PLL_Output_Frequency = 288/6 = 48MHz
PPRE1 = 2
APB1_Frequency = 24MHz
APB1_Frequency_Timer = 2*24MHz = 48MHz
The following line of code is what is buging me:
//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1; //Small delay
When this line is commented the period is 19.7ms and when is active the period is 20ms, as expected. It is very strange, this is how the generated code from CubeMX does. It makes the voltage scaling to 1 (low performance). I don't understand how seting the voltage scaling equals to 1 makes the PLL works correctly.
Down below is the code that configure the PLL:
void sys_clock_init(void){
int a;
//Sets the wait states to 1
FLASH->ACR |= 0x01;
a = FLASH->ACR; //Small delay
//Enables the power interface (for the power controller)
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
a = RCC->APB1ENR; //Small delay
//Clears the bits for the voltage scaling
PWR->CR1 &= ~(PWR_CR1_VOS);
//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1; //Small delay
//Makes HSI the source of the PLL
RCC->PLLCFGR &= ~(0x400000);
//Clears the bits for the different factors
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLM);
//Sets the PLLM = 0x08 = b100
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_3);
//Clears the PLLN bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN);
//Sets PLLN = 0x90 = b10010000
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_4);
//Clears the PLLP bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP);
//Sets the PLLP = 0x02 = b10
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLP_1);.
//Clears the PPRE1 bits
RCC->CFGR &= ~(RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_1 | RCC_CFGR_PPRE1_0);
//Set bit PPRE1 = 0x02 = b100
RCC->CFGR |= (RCC_CFGR_PPRE1_2);// | RCC_CFGR_PPRE1_0);
//Turns the PLL ON
RCC->CR |= RCC_CR_PLLON;
//Waits for the PLL to be ready
while(!((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY));
//Clears the switch bits
RCC->CFGR &= ~(RCC_CFGR_SW);
//Set the PLL as the System Clock
RCC->CFGR |= (RCC_CFGR_SW_1);}
I have also tested commenting the lines that sets VOS bits on the CubeMX code and the period is 19.75ms like mine.

This is my code to get that board to 16Mhz using the PLL and the external clock.
static int clock_init ( void )
{
unsigned int ra;
//switch to external clock.
ra=GET32(RCC_CR);
ra|=1<<16;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<17)) break;
if(1)
{
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=1;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==1) break;
}
//HSE ready
//PLLM aim for 2mhz so 8/4=2
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLP 16Mhz*8 = 128, 16MHz*6 = 96, not enough
//so PLLP is 8 VCO 128 so PLLN is 64
//don't really care about PLLQ but have to have something so 8
PUT32(RCC_PLLCFGR,0x20000000|(8<<24)|(1<<22)|(3<<16)|(64<<6)|(4<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
PUT32/GET32 are abstraction functions to do str/ldr. I will try either 48 HSE or 48Mhz HSI, and post what I find.
static int clock_init ( void )
{
unsigned int ra;
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//don't really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
The uart works, but that is not saying much.
With the default of scale 1 I do see that a little fast. but if I use the 8MHz HSE then it looks better. I use systick to count 120 seconds. set systick to roll over every 1million counts then wait for 120 rollovers, compare to a stopwatch/timer.
Next using 16000000 in systick and counting 900 rollovers that should be 5 minutes and it is to within a second since comparing visually to a timer is only that accurate. Using HSE, scaling 1 (default)
Using HSI scaling 1 it is off by a few seconds to get 19.7ns though would be a lot of seconds and I don't see that many.
Now using HSI scaling 3:
static int clock_init ( void )
{
unsigned int ra;
ra=GET32(RCC_APB1ENR);
ra|=1<<28; //PWR enable
PUT32(RCC_APB1ENR,ra);
PUT32(FLASH_ACR,0x00000001);
PUT32(PWR_CR1,0x4000);
GET32(PWR_CR1);
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//don't really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
Does appear to be more accurate. 5 minutes measured as 5 minutes to the second. So it appears perhaps that the documentation isn't correct with respect to the accuracy of HSI (as there is this exception using default scaling).
48Mhz -> 20.83ns
20.62 - 21.04 with the documented error.
There is a reason for using external clocks. If you are interested in more accuracy since you have the NUCLEO board use the external clock HSE not the internal HSI.
Hmmm, actually 1% for the 16Mhz which is 3% when multiplied by 3 to get 48MHz. I think using the divisor in the PLL makes it worse, but I would have to ponder that some more.
20.21 to 21.46 is the range you should see at the calibration temperature, then vary from that based on die temp.

Related

How do I properly draw a frame with an ILI9341? Arduino

I have a 2.8 inch TFT LCD from Adafruit driven by an ILI9341. To draw on the LCD, I use the commands 0x2A to set the width, 0x2B to set the height, and 0x2C to color each pixel (I2C). My problem is that I currently draw the background as a rectangle, and then each rectangle required. This creates a displeasing look since the colors start to mix and create disturbing, angled lines between the smaller rectangles. These are the functions I use to draw:
void drawRectangle(long sX, long sY, long eX, long eY, uint16_t clr) {
send32bitData(0x2A, (sX << 16) | eX);
send32bitData(0x2B, (sY << 16) | eY);
oneColor(clr, (eX - sX + 1) * (eY - sY + 1));
}
void oneColor(uint16_t clr, long area) {
uint8_t hi = clr >> 8;
uint8_t lo = clr;
uint8_t dHi = clr >> 6, bHi = clr >> 14, dLo = clr << 2, bLo = clr >> 6;
sendCommand(0x2C, true);
PORTC = 0x6;
for (long i = area; i--; i > 0) {
PORTC = 0x6;
PORTD = dHi;
PORTB = bHi;
PORTC = 0x2;
PORTC = 0x6;
PORTD = dLo;
PORTB = bLo;
PORTC = 0x2;
}
PORTC = 0x7;
}
Here's a video of that line. I'm assuming that I'm drawing wrong. I'd like to keep a huge array with colors for each pixel, but I have an Arduino Uno that 2048 bytes of variable space. If I had that array, then I would draw one rectangle for the whole screen and send each color to the memory. One thing that worked was drawing extremely slow. But, that's slow... I want to draw at ~70 fps while keeping each frame smooth.

Reading/writing to EEPROM - incorrect values

I'm using the Arduino IDE to program a ESP8266 board.
The idea is to play a sound of a random frequency for a random amount of time, and save the last frequency played to the EEPROM. Then, I have a watchdog ISR that restarts the board if the delay time is 4 seconds or more. When this happens and the board restarts, I want to play the last played frequency for 1 second, and then resume normal functionality again.
Here is my code,
#include <Ticker.h>
#include <EEPROM.h>
#define PIN_BUZZER 13 // the digital pin the Buzzer is attached to
PROGMEM const int freqs[] = {31, 49, 78, 123, 196, 311, 494, 784, 1245, 1976, 3136,
4978};
Ticker secondTick;
volatile int watchdogCount = 0;
volatile int freqIdx = 0; //the index that will store the last frequency before it restarts
int EEPROM_Addr = 42;
//The Watchdog Interrupt Service Routine (ISR)
void ISRwatchdog() {
watchdogCount++;
//The watchdog will be waken up when the couter reaches 4
if (watchdogCount == 4) {
ESP.restart(); //restarting the board
}
}
void setup() {
EEPROM.begin(4096);
Serial.begin(115200);
secondTick.attach(1, ISRwatchdog); //registering the watchdog ISR
pinMode(PIN_BUZZER, OUTPUT);
int prevFreq = EEPROM.read(EEPROM_Addr); // read previous frequency
if (prevFreq != 255){
Serial.println("Previous frequency found : ");
Serial.println(prevFreq);
analogWrite(PIN_BUZZER, 256);
analogWriteFreq(prevFreq);
delay(1000);
}
}
void loop() {
Serial.print("Watchdog counter = ");
Serial.println(watchdogCount);
watchdogCount = 0;
int freq = freqs[random(0, 11)];
Serial.print("Frequency: ");
Serial.println(freq);
Serial.println("Saving to EEPROM");
EEPROM.write(EEPROM_Addr, freq);
EEPROM.commit();
// generating 50% PWM
analogWrite(PIN_BUZZER, 256);
analogWriteFreq(freq);
//depending on the value of delay, the program may wake up the watchdog
int delayTime = random(1, 5) * 1000;
Serial.print("Delay time: ");
Serial.println(delayTime);
delay(delayTime);
}
The problem I'm facing is that values are either written to the EEPROM incorrectly or they are being read incorrectly. For example, here is some of the output I got,
Watchdog counter = 2
Frequency: 31
Saving to EEPROM
Delay time: 3000
Watchdog counter = 3
Frequency: 1245
Saving to EEPROM
Delay time: 4000
ets Jan 8 2013,rst cause:2, boot mode:(3,0)
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld
Previous frequency found :
221
The previous frequency in this case is incorrect.
And again in this output snippet,
Watchdog counter = 1
Frequency: 784
Saving to EEPROM
Delay time: 4000
Watchdog counter = 4
Frequency: 1976
Saving to EEPROM
Delay time: 1000
ets Jan 8 2013,rst cause:2, boot mode:(3,0)
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld
Previous frequency found :
184
There are some cases where my output is correct, but that is rare.
The EEPROM library for ESP8266 only stores one byte. That means it cannot store values over 255 -- the value you get back is least significant byte of the value you stored (i.e, freq % 256).
Consider storing the index of the value in the array instead of the value itself, e.g.
uint8_t idx = random(0, 11);
int freq = freqs[idx];
...
EEPROM.write(EEPROM_addr, idx);
and
uint8_t idx = EEPROM.read(EEPROM_addr);
int freq = freqs[idx];

Arduino pulse train

I will give you a little introduction:
I am working on a water fuel cell of Stanley Meyer. For those who don't know the water fuel cell you can see it here.
For the water fuel cell one has to build a circuit. Here is the diagram:
Right now I am working on the pulse generator (variable) and the pulse gate (variable) to generate this waveform.
So, I want to do this with Arduino timers. I already can generate a "high frequency" pulse generator (1 kHz - 10 kHz, depending on the prescaling at the TCCR2B register) PWM at pin 3 with this code:
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS21) | _BV(CS20);
OCR2A = 180;
OCR2B = 50;
I can modify the frequency and pulse with:
sensorValue = analogRead(analogInPin);
sensorValue2 = analogRead(analogInPin2);
// Map it to the range of the analog out:
outputValue = map(sensorValue, 0, 1023, 30, 220);
outputValue2 = map(sensorValue2, 0, 1023, 10, 90);
OCR2A = outputValue;
This is working fine.
Now I want to modulate this pulse with another pulse train with "low frequency" (20 Hz to 100 Hz approximately) to act as a pulse gate. I was thinking to use Timer 0 to count and shutdown the signal when it counts some value and activate when arrives at the same value again, like this
TCCR0A = _BV(COM0A0) | _BV(COM0B0) | _BV(WGM01);
TCCR0B = _BV(CS02);
OCR0A = 90;
OCR0B = OCR0A * 0.8;
And compare with the counter
if (TCNT0 <= OCR0A)
TCCR2A ^= (1 << COM2A0);
But it does not work well. Any ideas for this?
These days I have tried to create a wave generator like the one that comes in your question. I can not eliminate the jitter or mismatch that appears, but I can create a wave like that. Try this example and modify it:
#include <TimerOne.h>
const byte CLOCKOUT = 11;
volatile byte counter=0;
void setup() {
Timer1.initialize(15); // Every 15 microseconds change the state
// of the pin in the wave function giving
// a period of 30 microseconds
Timer1.attachInterrupt(Onda);
pinMode(CLOCKOUT, OUTPUT);
digitalWrite(CLOCKOUT, HIGH);
}
void loop() {
if (counter>=29) { // With 29 changes I achieve the amount of pulses I need.
Timer1.stop(); // Here I create the dead time, which must be in HIGH.
PORTB = B00001000;
counter = 0;
delayMicroseconds(50);
Timer1.resume();
}
}
void Onda(){
PORTB ^= B00001000; // Change pin status
counter += 1;
}

Arduino shield, SD card Data logge, why are my SD cards dying?

I'm having a real anoying problem that I carnt seem to find a solution on.
I have created a simple arduino code for sweeping a curve on 2 analog pin, controlled by a DAC unit. The sweeps are being done in real time, ones a second, and is stored on a SD card in files split into hours.
My problem is that my SPI interface on the SD cards stop responding during continues used.
I use the following arduino mega shield
http://pcb.daince.net/doku.php?id=data_logger
and a "Kingston MicroSDHC 4GB Secure Digital Card, 66X" for storage
I ran the the following code for 3 days and when I came back the SPI was none responding (I have done 1 hours tests before with no problem, and I have checked that the system changes files correctly)
#include "SPI.h"
#include <SD.h>
#include "Wire.h"
//Static definitions
#define ADG509_A0_pin 39
#define ADG509_A1_pin 38
#define SS_DAC_pin 53
#define voltage_analog_pin 11
#define current_analog_pin 12
#define led 13
#define DS1307_ADDRESS 0x68
#define chip_select 53
//Adjustable definitions
#define ADC_to_voltage 1/213 // the value for converting the arduino ADC to voltage
#define number_of_samples 100 //number of measurements, should be able to be divided by 4 without giving decimals
#define time_per_data_set 500 //the delay between datasets in milisecondss, note the the "delay = system_computation_time + time_per_data_set"
#define current_gain_ratio 2 //the realtion between the voltage level on the pin and current on from the solar pannel
#define voltage_gain_ratio 10 //the realtion between the voltage level on the pin and the voltage level from the solar panel
#define number_samples_per_measurement 5 //the number of ADC readings used to make an average of each measuring point, note this number greatly effects sweeping time
#define delay_per_measurement 1
void set_DAC(float value); // gets an input between 0.0 and 5.0 and sets the voltage to the value
void write_measurement_to_SD(float current, float voltage, int number); //writes the numbers to the SD card if initialized
void write_to_file(); //check is a new SD card file should be created and makes it ef nessesary. Also handles the data writing to the file
void get_time(); //Get the current time of the system, and store them in global variables
int bcdToDec(byte val); //Converts bytes to decimals numbers
char intToChar(int val, int number); //Converts integers to chars, only exept up to 2 dicimals
word output_word_for_DAC = 0; //used to type cast input of set_DAC to word before usage
byte data = 0; //temp variable need for DAC, it is the byte send over the communication
float volt; //stores a temporary voltage measurement
float current; //stores a temporary current measurement
float current_level; //stores the short curciut current level, it is used to find the optimal placement for measuring points
char filename[13] = "F0000000.txt"; //stores the current active filename for writing on the SD card
File dataFile; //the current version of the datafile on the SD card
int years, months, monthsDay, weekDay, hours, minute, seconds; //global varibles used to store the last time reading
float current_array[number_of_samples]; //used to store all current measurements points during sweep
float voltage_array[number_of_samples]; //used to store all voltage measurements points during sweep
int typecast_int; // used for typecasting float to int
int last_measurement_time;
int is_SDcard_there;
void setup() {
pinMode(ADG509_A0_pin, OUTPUT);
pinMode(ADG509_A1_pin, OUTPUT);
pinMode(SS_DAC_pin, OUTPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
digitalWrite(ADG509_A1_pin, LOW);
digitalWrite(ADG509_A0_pin, LOW);
SPI.begin(); // start up the SPI bus
SPI.setBitOrder(MSBFIRST);
Wire.begin();
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {;}
Serial.print("Initializing SD card...");
if (!SD.begin(chip_select)) {
Serial.println("Card failed, or not present");
is_SDcard_there = 0;
return;+
}
Serial.println("card initialized.");
is_SDcard_there = 1;
}
void loop() {
//finding the shortcurcuit current of the solar panel
get_time();
last_measurement_time = seconds;
set_DAC(5); //open fet
delayMicroseconds(1000);
current_level = analogRead(current_analog_pin);
for(float counter2 = 0; counter2 < 10; counter2++){
current_level += analogRead(current_analog_pin);
}
current_level = (current_level/10)* 1.1 * ADC_to_voltage;
//fully opening the fet to insure that the solar pannel is stable at max voltage before beginning the sweep
set_DAC(0); //ground fet
delayMicroseconds(10000);
if(is_SDcard_there == 1){
digitalWrite(led, HIGH);
}
//sweeping the first 80% current on the curve with 25% of the measuring points
//note no calculations should be put in here, since it slow the sweep down
for(float counter = 0; counter < number_of_samples * 0.25; counter++){
set_DAC((counter*current_level * 0.80) / (number_of_samples * 0.25));
delayMicroseconds(200);
current = analogRead(current_analog_pin);
volt = analogRead(voltage_analog_pin);
for(float counter2 = 0; counter2 < number_samples_per_measurement - 1; counter2++){
current += analogRead(current_analog_pin);
volt += analogRead(voltage_analog_pin);
}
current = current / number_samples_per_measurement;
volt = volt / number_samples_per_measurement;
typecast_int = counter;
current_array[typecast_int] = current;
voltage_array[typecast_int] = volt;
}
//sweeping the last 20% current on the curve with 75% of the measuring points
//note no calculations should be put in here, since it slow the sweep down
for(float counter = 0; counter < number_of_samples * 0.75; counter++){
set_DAC(current_level * 0.80 + (counter*current_level * 0.20) / (number_of_samples * 0.75));
delayMicroseconds(200);
current = analogRead(current_analog_pin);
volt = analogRead(voltage_analog_pin);
for(float counter2 = 0; counter2 < number_samples_per_measurement - 1; counter2++){
current += analogRead(current_analog_pin);
volt += analogRead(voltage_analog_pin);
}
current = current / number_samples_per_measurement;
volt = volt / number_samples_per_measurement;
typecast_int = counter + number_of_samples * 0.25;
current_array[typecast_int] = current;
voltage_array[typecast_int] = volt;
}
set_DAC(5); //sets DAC high to prepare for next short curcuit measurement
digitalWrite(led, LOW);
//converting data to desired values and writing them to the file
String to_write = "";
int check;
char buffer[20];
to_write = "0,0,-2";
to_write += '\r';
to_write += '\n';
to_write += "0,";
to_write += intToChar(minute,0);
to_write += intToChar(minute,1);
to_write += intToChar(seconds,0);
to_write += intToChar(seconds,1);
to_write += ",-1";
to_write += '\r';
to_write += '\n';
for(int counter = 0; counter < number_of_samples-1; counter++){
to_write += dtostrf(current_array[counter] = current_array[counter] * ADC_to_voltage * current_gain_ratio, 0, 2, buffer);
to_write += ",";
to_write += dtostrf(voltage_array[counter] = voltage_array[counter] * ADC_to_voltage * voltage_gain_ratio, 0, 2, buffer);
to_write += ",";
to_write += counter;
to_write += '\r';
to_write += '\n';
}
to_write += dtostrf(current_array[99] = current_array[99] * ADC_to_voltage * current_gain_ratio, 0, 2, buffer);
to_write += ",";
to_write += dtostrf(voltage_array[99] = voltage_array[99] * ADC_to_voltage * voltage_gain_ratio, 0, 2, buffer);
to_write += ",99";
Serial.println(to_write); //should only be used for debugging since it slow down the system to much
compute_filename(); //initialize a new filename if needed
check = 0;
while(check == 0 && is_SDcard_there == 1){
dataFile = SD.open(filename,FILE_WRITE);
check = dataFile.println(to_write);
if (dataFile){
dataFile.close();
}
}
//wait for next seconds
while(last_measurement_time + delay_per_measurement > seconds){
get_time();
if(seconds < last_measurement_time){seconds = seconds + 60;}
}
}
// gets an input between 0.0 and 5.0 and sets the voltage to the value
void set_DAC(float value){
if(value <= 5){
value = value*819;
int conveter = value;
output_word_for_DAC = conveter;
digitalWrite(SS_DAC_pin, LOW);
data = highByte(output_word_for_DAC);
data = 0b00001111 & data;
data = 0b00110000 | data;
SPI.transfer(data);
data = lowByte(output_word_for_DAC);
SPI.transfer(data);
digitalWrite(SS_DAC_pin, HIGH);
}
}
//writes the numbers to the SD card if initialized
void write_measurement_to_SD(float current, float voltage, int number){
dataFile = SD.open(filename,FILE_WRITE);
dataFile.print(current);
dataFile.print(',');
dataFile.print(voltage);
dataFile.print(',');
dataFile.print(number);
dataFile.println(';');
if (dataFile){
dataFile.close();
}
}
//Converts bytes to decimals numbers
int bcdToDec(byte val){
return ( (val/16*10) + (val%16) );
}
//Converts integers to chars, only exept up to 2 dicimals
char intToChar(int val, int number){ // note it only take ints with 2 digits
String tempString = "";
char returnValue[3];
if(val < 10){
tempString += 0;
}
tempString += val;
tempString.toCharArray(returnValue,3);
return returnValue[number];
}
//Get the current time of the system, and store them in global variables
void get_time(){
Wire.beginTransmission(DS1307_ADDRESS);
byte zero = 0x00;
Wire.write(zero);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
seconds = bcdToDec(Wire.read());
minute = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0b111111); //24 hours time
weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
monthsDay = bcdToDec(Wire.read());
months = bcdToDec(Wire.read());
years = bcdToDec(Wire.read());
}
//check if the system need a new filename
void compute_filename(){
get_time();
filename[1] = intToChar(years,1);
filename[2] = intToChar(months,0);
filename[3] = intToChar(months,1);
filename[4] = intToChar(monthsDay,0);
filename[5] = intToChar(monthsDay,1);
filename[6] = intToChar(hours,0);
filename[7] = intToChar(hours,1);
if (dataFile){
dataFile.close();
}
}
I know that this is a big code dump and I'm sorry for that, but I carnt realy cut it down when I have no idea what is killing my SD cards.
Any help on the matter is appreciated
and any ideas on what I can test to isolate or locate the error is also welcome
there can be 2 possible errors:
1 resource leak
2 RAM overflow
for 1 you can put some code that write on serial RAM usage evry loop(), if that number grow, some library (as you aren't allocating memory with alloc() )is broken. For 2, don't build up to_write, but use directly Serial.println(), alyas try to use array/string wicth use LESS than 100 byte or you might have problem (String dinamically allocate space, and that allocation can fail.. silently. then bad things appen)
I've done a lot of work with SD cards during the past 10 years and I've noticed that the SD card is very easily bricked into a non-responsive mode if it receives garbage in the CMD line. It seems that at least some kind of garbage is interpreted as a command to set the card password, thus locking the card. It has happened to me at least 10 times in as many years when I've been working with SD library code or new hardware designs, so it looks to me that it must be some bit patterns which is easily generated somehow.
I've been able to rescue the (micro)SD cards by putting them into my old Symbian phone which immediately recognizes that the card is locked and offers to reformat the card and reset the password. You might try the same with your SD card, to see if your problem is the same I've experienced. I remember vaguely that some cheap Canon camera was also able to rescue some card in a similar way.

Why does XBee transmit fail sometimes?

I doing a project with Arduino Uno R3 and XBee S2 transmission. I use a couple of sensors like a wireless (RF) temperature sensor, two SHT75 sensors, a 3-axis accelerometer and an illumination sensor. And after collecting the data, we use XBee (S2, API mode) to send the data to the gateway. Every round is about one second.
The first problem is the data is about 16 bytes, but the packet does not send successful every round. Sometime it works, and sometimes it doesn't, but the payload of XBee can be 60 or 70 bytes in the datasheet... But if I put the payload as some simply an integer (like 1, 2, 3), not the data from sensor, and the transmission will be stable.
After meeting the problem above, I divided the data into two packets (each with an eight bytes payload), and the first packet is very stable, but the second is very unstable. As mentioned above, if I put some number into the second packets instead of the sensing data the second packet will become stable and send successfully every round.
So I think it's the code problem, but idk where is the problem. I try to change the baud rate or increasing the delay time between the two packets. Where is the problem? The following is my code:
#include <XBee.h>
#include <i2cmaster.h>
#include <string.h>
#include <ctype.h>
#include <Sensirion.h>
#include "Wire.h"
#include "MMA845XQ.h"
**///////////////////////////// XBee setup //////////////////////////////////**
XBee xbee = XBee();
XBeeAddress64 remoteAddress = XBeeAddress64(0x00000000, 0x00000000);
ZBRxResponse zbRx = ZBRxResponse();
ZBTxStatusResponse zbTxStus = ZBTxStatusResponse();
uint8_t payload[] = {0,0,0,0,0,0,0,0,0};
uint8_t payload1[] = {0,0,0,0,0,0,0,0,0};
**///////////////////////////// Accelerometer //////////////////////////////////**
MMA845XQ accel;
**////////////////////////// SHT1 serial data and clock ////////////////////**
const byte dataPin = 2;
const byte sclkPin = 3;
Sensirion sht = Sensirion(dataPin, sclkPin);
unsigned int rawData;
float temperature;
float humidity;
byte stat;
**////////////////////////// SHT2 serial data and clock ////////////////////**
const byte dataPin1 = 4;
const byte sclkPin1 = 5;
Sensirion sht1 = Sensirion(dataPin1, sclkPin1);
unsigned int rawData1;
float temperature1;
float humidity1;
byte stat1;
**//////////////////////////// Illumination sensor ////////////////////////**
int sensorPin = A0; // Select the input pin for the potentiometer
int sensorValue = 0; // Variable to store the value coming from the sensor
long int pardata, pardata_low, pardata_hi, real_pardata;
uint16_t illumindata = 0;
void setup () {
i2c_init(); //Initialise the I²C bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //Enable pullups
Wire.begin();
accel.begin(false, 2);
Serial.begin(115200);
xbee.begin(Serial);
}
void loop () {
payload[0] = 10;
payload1[0] = 11;
**/////////////////////RF temperature sensor/////////////////////////////**
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // Zero out the data
int frac; // Data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
celcius *= 100;
int a = int(celcius) + 1;
payload[1] = a >> 8 & 0xff;
payload[2] = a & 0xff;
**//////////////////////////// Illumination sensor ////////////////////////////////**
sensorValue = analogRead(sensorPin);
TSR(sensorValue);
payload[3] = pardata_low >> 8 & 0xff;
payload[4] = pardata_low & 0xff;
**//////////////////////////// 3-axis accelemeter sensor ////////////////////////////////**
accel.update();
payload[5] = accel.getX()*10;
payload[6] = accel.getY()*10;
payload[7] = accel.getZ()*10;
delay(100);
**////////////////////////////// XBee send first packet///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, payload, sizeof(payload));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
**//////////////// SHT 1x temperature and humidity sensor /////////////////////////**
sht.readSR(&stat); // Read sensor status register
sht.writeSR(LOW_RES); // Set sensor to low resolution
sht.readSR(&stat); // Read sensor status register again
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht.meas(TEMP, &rawData, NONBLOCK);
temperature = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
humidity = sht.calcHumi(rawData, temperature);
sht.meas(HUMI, &rawData, NONBLOCK);
humidity = sht.calcHumi(rawData, temperature);
temperature *= 100;
a = int(temperature) + 1;
payload1[1] = a >> 8 & 0xff;
payload1[2] = a & 0xff;
humidity *= 100;
a = int(humidity) + 1;
payload1[3] = a >> 8 & 0xff;
payload1[4] = a & 0xff;
delay(10);
sht1.readSR(&stat1);
sht1.writeSR(LOW_RES); // Set sensor to low resolution
sht1.readSR(&stat1);
sht1.measTemp(&rawData1); // sht.meas(TEMP, &rawData, BLOCK)
temperature1 = sht1.calcTemp(rawData1);
sht1.measHumi(&rawData1); // sht.meas(HUMI, &rawData, BLOCK)
humidity1 = sht1.calcHumi(rawData1, temperature1);
delay(10);
temperature1 *= 100;
a = int(temperature1) + 1;
payload1[5] = a >> 8 & 0xff;
payload1[6] = a & 0xff;
humidity1 *= 100;
a = int(humidity1) + 1;
payload1[7] = a >> 8 & 0xff;
payload1[8] = a & 0xff;
**////////////////////////////// XBee send second packet ///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
zbTx = ZBTxRequest(remoteAddress,payload1, sizeof(payload1));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
}
void TSR(int sensorValue)
{
illumindata = (sensorValue * 4 * 5) / 1.5;
pardata = 6250/6144*illumindata*10;
if(pardata > 0)
{
if(pardata < 11500)
{
real_pardata = 0.0000000020561*pardata*pardata*pardata -
0.00002255*pardata*pardata +
0.25788*pardata -
6.481;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
else
{
real_pardata = 0.0000049204*pardata*pardata*pardata -
0.17114*pardata*pardata +
1978.7*pardata -
7596900;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
}
else
{
pardata_hi = 0;
pardata_low = 0;
}
}
as I am writing this I have solved the same problem you have, though with similar hardware setup. I have used bare avr atxmega128a3u (so no arduino board) and an Xbee S1 communicating on baud rate 115200. After a few days trying to figure this out I came to conclusion, that if your avr is not running at precise clock (external xtal) and you use slightly "faster" baud rate ( >= 115200 ) Xbee's serial hardware has probably trouble recovering clock signal resulting in errors in transmission. (Maybe Xbee has slow bit sampling rate).
Anyway, by ensuring your microprocessor is running at stable clock (you should be safe here 'cause arduino has an external xtal) and by using slower baud rate (try 57600, 19200 or 9600) should solve your problem. I hope so. :) ...And don't forget to reconfigure Xbee's baud rate in XCTU.
And also it might help if you initliaze xbee only once.Move these lines into setup() function:
setup(){
// This is changed
Serial.begin(9600);
// This is new
xbee = XBee();
xbee.begin(Serial);
// ...
}
EDIT: Also you might be interested in this website where you can see what is the % of error for given clock frequency and baud rate (as well as direct register values to set if you were using bare avr) http://www.wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=16&hidetables=1

Resources