0

I'm trying to use a MS5540C (digital pressure sensor) and the sample code has this line:

 TCCR1B = (TCCR1B & 0xF8) | 1; //generates the MCLK signal

I'm a bit of a noob to the IoT but its not beyond me to check the SPI.h and see that there is indeed no declaration.

I'm using an Arduino UNO WiFi Rev 2. (Seems like its pins are quit different from an UNO) I have noted in the comments that Im using pins 32,33,34 instead of 11,12,13

I'm not 100% sure what to ask ... other than Is there a replacement call/function/method that should replace that line? ..or am I missing something else totally. As it stands now...when the program runs its results are inconsistent. I'm just commenting out the faulty line to get it to compile.

Complete sketch source: Future Electronics

/*
 MS5540C Miniature Barometer Module
 This program will read your MS5440C or compatible pressure sensor every 5 seconds and show you the calibration words, the calibration factors,
 the raw values and the compensated values of temperature and pressure.
 Once you read out the calibration factors you can define them in the header of any sketch you write for the sensor.
 Uno Pins:
 MS5540 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9 (or use external clock generator on 32kHz)
 CS is not in use, but might be pin 10
 ==[ addendum start]=============================
 Uno WiFi Rev2 Pins:
 MOSI: pin 32
 MISO: pin 33
 SCK: pin 34
 MCLK: pin 9 (or use external clock generator on 32kHz)
 ==[ addendum end ]=============================
 created 29 February 2012
 by MiGeRA
*/
/*
 Calibration of my sensor example ...
 Calibration word 1 = 46958
 Calibration word 2 = 65369
 Calibration word 3 = 39392
 Calibration word 4 = 45914
 c1 = 23479
 c2 = 2074
 c3 = 717
 c4 = 615
 c5 = 1021
 c6 = 25
*/
#include <SPI.h>
const int clock = 9;
void setup() {
 Serial.begin(9600);
 SPI.begin(); //see SPI library details on arduino.cc for details
 SPI.setBitOrder(MSBFIRST);
 SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
 pinMode(clock, OUTPUT);
 delay(100);
}
void loop()
{
 Serial.println("=====================================================================");
 TCCR1B = (TCCR1B & 0xF8) | 1; //generates the MCLK signal
 analogWrite (clock, 128) ;
 resetsensor(); //resets the sensor - caution: afterwards mode = SPI_MODE0!
 //Calibration word 1
 unsigned int result1 = 0;
 unsigned int inbyte1 = 0;
 SPI.transfer(0x1D); //send first byte of command to get calibration word 1
 SPI.transfer(0x50); //send second byte of command to get calibration word 1
 SPI.setDataMode(SPI_MODE1); //change mode in order to listen
 result1 = SPI.transfer(0x00); //send dummy byte to read first byte of word
 result1 = result1 << 8; //shift returned byte
 inbyte1 = SPI.transfer(0x00); //send dummy byte to read second byte of word
 result1 = result1 | inbyte1; //combine first and second byte of word
 Serial.print("Calibration word 1 = ");
 Serial.print(result1, HEX);
 Serial.print(" ");
 Serial.println(result1);
 resetsensor(); //resets the sensor
 //Calibration word 2; see comments on calibration word 1
 unsigned int result2 = 0;
 byte inbyte2 = 0;
 SPI.transfer(0x1D);
 SPI.transfer(0x60);
 SPI.setDataMode(SPI_MODE1);
 result2 = SPI.transfer(0x00);
 result2 = result2 << 8;
 inbyte2 = SPI.transfer(0x00);
 result2 = result2 | inbyte2;
 Serial.print("Calibration word 2 = ");
 Serial.print(result2, HEX);
 Serial.print(" ");
 Serial.println(result2);
 resetsensor(); //resets the sensor
 //Calibration word 3; see comments on calibration word 1
 unsigned int result3 = 0;
 byte inbyte3 = 0;
 SPI.transfer(0x1D);
 SPI.transfer(0x90);
 SPI.setDataMode(SPI_MODE1);
 result3 = SPI.transfer(0x00);
 result3 = result3 << 8;
 inbyte3 = SPI.transfer(0x00);
 result3 = result3 | inbyte3;
 Serial.print("Calibration word 3 = ");
 Serial.print(result3, HEX);
 Serial.print(" ");
 Serial.println(result3);
 resetsensor(); //resets the sensor
 //Calibration word 4; see comments on calibration word 1
 unsigned int result4 = 0;
 byte inbyte4 = 0;
 SPI.transfer(0x1D);
 SPI.transfer(0xA0);
 SPI.setDataMode(SPI_MODE1);
 result4 = SPI.transfer(0x00);
 result4 = result4 << 8;
 inbyte4 = SPI.transfer(0x00);
 result4 = result4 | inbyte4;
 Serial.print("Calibration word 4 = ");
 Serial.print(result4, HEX);
 Serial.print(" ");
 Serial.println(result4);
 //now we do some bitshifting to extract the calibration factors
 //out of the calibration words;
 long c1 = (result1 >> 1) & 0x7FFF;
 long c2 = ((result3 & 0x003F) << 6) | (result4 & 0x003F);
 long c3 = (result4 >> 6) & 0x03FF;
 long c4 = (result3 >> 6) & 0x03FF;
 long c5 = ((result1 & 0x0001) << 10) | ((result2 >> 6) & 0x03FF);
 long c6 = result2 & 0x003F;
 Serial.print("c1 = ");
 Serial.println(c1);
 Serial.print("c2 = ");
 Serial.println(c2);
 Serial.print("c3 = ");
 Serial.println(c3);
 Serial.print("c4 = ");
 Serial.println(c4);
 Serial.print("c5 = ");
 Serial.println(c5);
 Serial.print("c6 = ");
 Serial.println(c6);
 resetsensor(); //resets the sensor
 //Pressure:
 unsigned int presMSB = 0; //first byte of value
 unsigned int presLSB = 0; //last byte of value
 unsigned int D1 = 0;
 SPI.transfer(0x0F); //send first byte of command to get pressure value
 SPI.transfer(0x40); //send second byte of command to get pressure value
 delay(35); //wait for conversion end
 SPI.setDataMode(SPI_MODE1); //change mode in order to listen
 presMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
 presMSB = presMSB << 8; //shift first byte
 presLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
 D1 = presMSB | presLSB; //combine first and second byte of value
 Serial.print("D1 - Pressure raw = ");
 Serial.println(D1);
 resetsensor(); //resets the sensor
 //Temperature:
 unsigned int tempMSB = 0; //first byte of value
 unsigned int tempLSB = 0; //last byte of value
 unsigned int D2 = 0;
 SPI.transfer(0x0F); //send first byte of command to get temperature value
 SPI.transfer(0x20); //send second byte of command to get temperature value
 delay(35); //wait for conversion end
 SPI.setDataMode(SPI_MODE1); //change mode in order to listen
 tempMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
 tempMSB = tempMSB << 8; //shift first byte
 tempLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
 D2 = tempMSB | tempLSB; //combine first and second byte of value
 Serial.print("D2 - Temperature raw = ");
 Serial.println(D2); //voila!
 //calculation of the real values by means of the calibration factors and the maths
 //in the datasheet. const MUST be long
 const long UT1 = (c5 << 3) + 20224;
 const long dT = D2 - UT1;
 const long TEMP = 200 + ((dT * (c6 + 50)) >> 10);
 const long OFF = (c2 * 4) + (((c4 - 512) * dT) >> 12);
 const long SENS = c1 + ((c3 * dT) >> 10) + 24576;
 const long X = (SENS * (D1 - 7168) >> 14) - OFF;
 long PCOMP = ((X * 10) >> 5) + 2500;
 float TEMPREAL = TEMP / 10;
 float PCOMPHG = PCOMP * 750.06 / 10000; // mbar*10 -> mmHg === ((mbar/10)/1000)*750/06
 /*
 Serial.print("UT1 = ");
 Serial.println(UT1);
 Serial.print("dT = ");
 Serial.println(dT);
 Serial.print("TEMP = ");
 Serial.println(TEMP);
 Serial.print("OFFP = ");
 Serial.println(OFF);
 Serial.print("SENS = ");
 Serial.println(SENS);
 Serial.print("X = ");
 Serial.println(X);
 */
 Serial.print("Real Temperature in C = ");
 Serial.println(TEMPREAL);
 Serial.print("Compensated pressure in mbar = ");
 Serial.println(PCOMP);
 Serial.print("Compensated pressure in mmHg = ");
 Serial.println(PCOMPHG);
 //2-nd order compensation only for T < 20°C or T > 45°C
 long T2 = 0;
 float P2 = 0;
 if (TEMP < 200)
 {
 T2 = (11 * (c6 + 24) * (200 - TEMP) * (200 - TEMP) ) >> 20;
 P2 = (3 * T2 * (PCOMP - 3500) ) >> 14;
 }
 else if (TEMP > 450)
 {
 T2 = (3 * (c6 + 24) * (450 - TEMP) * (450 - TEMP) ) >> 20;
 P2 = (T2 * (PCOMP - 10000) ) >> 13;
 }
 if ((TEMP < 200) || (TEMP > 450))
 {
 const float TEMP2 = TEMP - T2;
 const float PCOMP2 = PCOMP - P2;
 float TEMPREAL2 = TEMP2 / 10;
 float PCOMPHG2 = PCOMP2 * 750.06 / 10000; // mbar*10 -> mmHg === ((mbar/10)/1000)*750/06
 Serial.print("2-nd Real Temperature in C = ");
 Serial.println(TEMPREAL2);
 Serial.print("2-nd Compensated pressure in mbar = ");
 Serial.println(PCOMP2);
 Serial.print("2-nd Compensated pressure in mmHg = ");
 Serial.println(PCOMPHG2);
 }
 delay(5000);
}
void resetsensor() //this function keeps the sketch a little shorter
{
 SPI.setDataMode(SPI_MODE0);
 SPI.transfer(0x15);
 SPI.transfer(0x55);
 SPI.transfer(0x40);
}
Juraj
18.3k4 gold badges31 silver badges49 bronze badges
asked Oct 3, 2019 at 19:14
2
  • Haave you written this code yourself, or did you copy parts of it somewhere? If the least, plase link to that source Commented Oct 3, 2019 at 19:22
  • @chrisl I added the source above. If you copy the text..take note of a char that is the 'f" and the 'l' combined!...ie in "float"...just retype it. Commented Oct 3, 2019 at 19:30

1 Answer 1

3

While writing this answer, I found out about the register emulation of the Arduino Uno Wifi. The Uno Wifi is a different chip, than the Uno, thus you have different registers. But the Uno Wifi was thought as a drop in replacement, so register emulation maps the old register names to the new registers, so that you can basically simply reuse the old code for the Uno. In my Arduino IDE (v1.8.9) I had a buildin Uno Wifi board, which seems to have the register emulation enabled without configuration option (I could compile your sketch even for the Uno Wifi). Through the board manager I installed the "Arduino megaAVR Boards" core, that contains the Arduino Uno Wifi rev2. If you choose this board in the board selection, you get the option to select the register emulation. For old code you need the emulation for ATmega328. With that, your old code should compile.

This makes the rest of my answer unnecessary, but since I already spend some time writing it, I will leave it in the answer for information and for the case, that you don't want to use the register emulation.


You get the error, because the sketch, that you copied is made for the Arduino Uno, not the Arduino Uno Wifi. While the first uses an ATmega328P chip, the last is build with an ATmega4809 (you can find this information here at the Arduino.cc store). These are different chips, thus you cannot simply reuse code that is made for the Uno on the Uno Wifi.

TCCR1B is the control register B of Timer 1. This name is specific to the ATmega328P chip. The ATmega4809 has even more timers than the 328P, but they seem to get configured via different registers. Refer to the datasheets on the product site of the ATmega4809. The timer hardware and it's registers are described in the more general megaAVR 0 series family datasheet. At the first glance it seems, that not only the register description is different from the 328P, but also the positions of the different configurations. This means, that every code, that uses direct register manipulations for the timer, must be rewritten for the 4809.

Fortunately, I see only 1 line here, that does this: The line, that generated the compiler error. (The SPI library very likely already has fitting definitions inside for the 4809). You have the line

TCCR1B = (TCCR1B & 0xF8) | 1;

That clears the 3 least significant bits (leaving the rest as it was) and setting the least significant bit to 1. According to chapter 16.11.2 of the 328P's datasheet (description of the TCCR1B register), these 3 bits are the clock selection. A bit code of 001 (only least significant bit set) means timer on, but with no prescaling.

To be honest, I'm not sure, if this line really does something, since directly after that, analogWrite() is called and I thought this function would overwrite the timer settings. But other posts (like this one) suggest, that it at least does not overwrite the clock selection.

I don't know, which timer get's used for outputting PWM to that pin, but for now, I will assume the first timer of type B. If you look into the families datasheet (as linked above) the clock source of the second timer (TCB) is configured with the register TCB0.CTRLA (see chapter 20.5.1). Bits 1 and 2 are configuring the prescaler (binary 00 for no prescaler), bit 0 enables the timer. So you can again write binary 001 to this register, leaving the rest untouched. So I suggest, you use this line instead of the old one

TCB0.CTRLA = (TCB0.CTRLA & 0xF8) | 1;

This should do the same with the second timer, that was done in the original sketch. If the first timer is used for this, you would have to change TCB0 to TCA0.SINGLE (I really don't know, why this SINGLE is needed) and change 0xF8 to 0xF0, since TCA has 3 bits for selecting the clock source.

answered Oct 3, 2019 at 21:17
3
  • I might be a little over my head. I do have the right board in boardmanager. I had also tried changing the emulation. I still get the error! My initial thoughts were the preprocessor was boogering up the code. The calibration words keep changing. I can see now Im going to have to get a grip on registers,clocks..etc..etc. Commented Oct 3, 2019 at 23:22
  • I think the emulation doesn't cover timers Commented Oct 4, 2019 at 7:32
  • @Juraj But the old code compiles for me only with register emulation. Doesn't that mean, that it also does the emulation for the timer registers? Commented Oct 4, 2019 at 7:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.