Go Down

Topic: Very basic SPI (and C++?) questions (Read 1 time) previous topic - next topic

sendung

Jan 16, 2012, 10:14 am Last Edit: Jan 16, 2012, 10:42 am by sendung Reason: 1
Hi!

I'm pretty much a newbie regarding Arduino and microcontrollers, but I have some background in programming (Python, PHP, Perl). My project: log my energy consumption to the internet in real time. The intended setup would contain multiple sensor/transmitter units and one logger/receiver unit with ethernet connection. For wireless communication between sensor and logger unit I'd like to try out the Hoperf RFM01 receiver and RFM02 transmitter, since they are cheap and available.

My goal is to actually understand what I'm doing. Since the RFM01/02 use SPI for configuration and optionally for data transfer from/to the modules, my first challenge is to get to know SPI. I figured that it would be worthwhile using the SPI library delivered with Arduino.

So here I am, trying to send a "Read Status Command" to my RFM01 module (supposed to be any command starting with bit 0). The strange thing is that I get an output without me knowingly returning any response from anywhere.

The output is:

Starting setup
Empty RFM01 status: 0
RFM01 status DEC:1028 BIN:10000000100 HEX:404
Setup done


How can it be that the variable rfm01stat changes its value when getRfm01Status() doesn't actually return anything? Or is it returning something without me using a return X statement?

If 10000000100 is actually the response from the Status Read Command, I have no Idea how it got returned into my variable. Which means I haven't understood the SPI library code at all. On the other hand, if it's just some garbage, I'd like to know ehre it comes from and how I can return the response for the status command.

Here is my little bit of code so far:

Code: [Select]
// talking to a RFM01 receiver via SPI

// board configuration settings
const int slaveSelectPin = 10;  // slave select (a.k.a. SS or CSB or Chip Select) pin on the Arduino board
/*
Not configurable since fixed in SPI library:
- master out, slave in (MOSI or SDI) on pin 11 of the Arduino board
- master in, slave out (MISO or SDO) on pin 12 of the Arduino board
- serial clock (SCK or SCLK) on pin 13 of the Arduino board
*/

// we communicate with the RF01 via SPI, so we need the lib
#include <SPI.h>

void setup() {
 Serial.begin(9600);
 Serial.println("\n");
 Serial.println("Starting setup");

 // initalize the  data ready and slave select pins
 pinMode(slaveSelectPin, OUTPUT);
 
 // start the SPI library:
 SPI.begin();

 setup_rfm01();
 
 Serial.println("Setup done");
}

void loop() {
 // TODO: receive data
 delay(1000);
}

/**
* Sets up the RFM01 receiver to certain fixed settings
*/
void setup_rfm01() {
 delay(250); // give the RFM01 some time
 
 unsigned int rfm01stat;
 Serial.print("Empty RFM01 status: ");
 Serial.println(rfm01stat);
 
 rfm01stat = getRfm01Status();
 Serial.print("RFM01 status DEC:");
 Serial.print(rfm01stat, DEC);
 Serial.print(" BIN:");
 Serial.print(rfm01stat, BIN);
 Serial.print(" HEX:");
 Serial.print(rfm01stat, HEX);
 Serial.println("");
 
 // lot of stuff remaining TODO
}

/**
* Write data to the RFM01 module
*/
void writeToRfm01(int command) {
 SPI.setBitOrder(MSBFIRST);           // RFM01 always requires most significant bit first
 SPI.setClockDivider(SPI_CLOCK_DIV8); // We explicitly set SPI frequency to 0.25 * chip frequency.
 SPI.setDataMode(SPI_MODE0);
 digitalWrite(slaveSelectPin, LOW);
 SPI.transfer(command);
 digitalWrite(slaveSelectPin, HIGH);
}

/**
* Get RFM01 status
*/
unsigned int getRfm01Status() {
 writeToRfm01(0);
 
 // TODO: decode return message
 /* What the status response bits mean:
   1: FIFO IT Number of the data bits in the FIFO has reached the preprogrammed limit
   2: FFOV FIFO overflow
   3: WK-UP Wake-up timer overflow
   4: LBD Low battery detect, the power supply voltage is below the preprogrammed limit
   5: FFEM FIFO is empty
   6: DRSSI The strength of the incoming signal is above the preprogrammed limit
   7: DQD Data Quality Detector detected a good quality signal
   8: CRL Clock recovery lock
   9: ATGL Toggling in each AFC cycle
   10: ASAME AFC stabilized (measured twice the same offset value)
   11-16: OFFS6, 4-0 Offset value to be added to the value of the Frequency control word
 */
}



Thanks!

PaulS

Quote
How can it be that the variable rfm01stat changes its value when getRfm01Status() doesn't actually return anything? Or is it returning something without me using a return X statement?

If getRfm01Status() doesn't actually return anything, why are you assigning that nothing to rfm01stat?

If getRfm01Status() is supposed to return something, why don't you?

What is happening is that getRfm01Status() is defined as returning a value, so, when it returns, the value that it is supposed to return is popped off the stack and assigned to the variable. What is on the stack at that point? Garbage, because the return statement that is supposed to put the value on the stack is missing.

The compiler actually generates a warning that you have failed to use the return statement, but the Arduino team doesn't want to confuse you, so they suppress the warning. That is supposed to make it better for you. Is it working?

sendung

Quote
If getRfm01Status() doesn't actually return anything, why are you assigning that nothing to rfm01stat?


Because I actually WANT to get something back into rfm01stat.

Quote
If getRfm01Status() is supposed to return something, why don't you?


Because I wanted to understand first why the variable is changed without me returning anything. And because I havent figured out yet how to get a response (or however that would be called) from a SPI command.

Quote
What is happening is that getRfm01Status() is defined as returning a value, so, when it returns, the value that it is supposed to return is popped off the stack and assigned to the variable. What is on the stack at that point? Garbage, because the return statement that is supposed to put the value on the stack is missing.


That is the sort of clarification I was hoping for!

Quote
The compiler actually generates a warning that you have failed to use the return statement, but the Arduino team doesn't want to confuse you, so they suppress the warning. That is supposed to make it better for you. Is it working?


Well, in this case, not quite. But that explains a lot. It means that I am not too far of with my heritage from PHP, Python and Perl.

Thanks for your response!

All I have to do know is to find out how I can send a command 0 and catch the response to that command. As far as I understand from other code examples, SPI.transfer() returns the response byte by byte. Let's see...

PaulS

The thing with the warnings being turned off, and there being no way to turn them on is particularly annoying. The reason is that a lot of the core code generates warnings when compiled, and the Arduino team apparently doesn't want us to know that they haven't fixed all the warnings in their code.

Some of them would take a not-insignificant amount of time to address, but the warnings should be resolved, in my opinion.

The option, at least, of seeing warnings, should be provided. Ideally, the warnings would be separated from the often verbose output of the compiler, so that the warnings are obvious.

In the past week, there has been quite a bit of discussion on the forum about signed/unsigned comparison issues. There is a warning for that. Show it, to avoid tripping an unwary programmer. It's certainly easier to fix (or ignore) a problem like that than to discover faulty behavior in code and struggle to understand why something that compiles "successfully" fails so miserably.

sixeyes

Paul,

Have you done a clean install with v1.0?

I did last month and I'm getting all the warnings, including unsigned / signed comparisons. I gather that if you upgrade it doesn't enable the warnings.

They seem to have fixed a lot of the library code so you only get a warning from Tone.cpp but I've "fixed" that in my library (http://arduino.cc/forum/index.php/topic,85840).

Iain

PaulS

Quote
Have you done a clean install with v1.0?

I did, but I haven't used it that much.

Quote
I did last month and I'm getting all the warnings, including unsigned / signed comparisons.

I'll check it out.

fat16lib

You can enable or disable warning from the 1.0 IDE.

Select preferences from the file menu.  Check "Show verbose output during: compile".

This will cause warnings to be listed in red during compile.

Kev_

Hi,

I want to experiment with the RFM01 as well. (On an Arduino Nano)
But I'm not sure how I have to connect the rfm to the arduino board.
I read through the rfm01 pdf from hoperf but I'm a bit confused now as the rfm can work in different modes (Polling/Interrupt and FIFO Bufferd) and I'm not sure which pins I need for which mode.

At the moment I've got connected:

(RFM01 -> Arduino)
Power:
VDD -> 5V
GND -> GND

SPI:
nSel -> D10 (SS)
SDI -> D11 (MOSI)
SDO -> D12 (MISO)
SCK -> D13 (SCK)

Is that right? Do I need additional ports?

Thanks for any hint.

  • http://www.hoperf.com/upload/rf/RFM01.pdf

Left01

HI Kev_
The RFM01 works in several modes. here is code from the data sheet i found online. arduino nano(3.0) uses atmega328p which is has few differences with atmega48 but i guess the pin numbering will not change.here is the code that will guide you on pin usage

/********************************************************************
copyright (c) 2006
Title: RF01 simple example based on AVR C
Current version: v1.0
Function: Package Receive Demo
processor ATMEGA48
Clock: 10MHz Crystal
Operate frequency: 434MHz
Data rate: 4.8kbps
Package size: 23byte
Author: Tank
Company: Hope microelectronic Co.,Ltd.
Contact: +86-0755-86106557
E-MAIL:hopefsk@hoperf.com
Date: 2006-10-24

Connections
ATMEGA48 SIDE   RF01 SIDE
SCK--------------->SCK
MISO<---------------SDO
MOSI--------------->SDI
SS--------------->nSEL
DATA:Pull up to VDD
INT0<---------------nIRQ
PC0~PC3: LED0~LED3
**********************************************************************/

#include <mega48.h>

#define DDR_IN 0
#define DDR_OUT 1

#define PORT_SEL PORTB
#define PIN_SEL PINB
#define DDR_SEL DDRB

#define PORT_SDI PORTB
#define PIN_SDI PINB
#define DDR_SDI DDRB

#define PORT_SCK PORTB
#define PIN_SCK PINB
#define DDR_SCK DDRB

#define PORT_SDO PORTB
#define PIN_SDO PINB
#define DDR_SDO DDRB

#define PORT_LED PORTC
#define DDR_LED DDRC

#define PB7      7//--/
#define PB6      6// |
#define RFXX_SCK   5// |
#define RFXX_SDO   4// |RF_PORT
#define RFXX_SDI   3// |
#define RFXX_SEL   2// |
#define RFXX_DATA   1// |
#define PB0      0//--/

#define SEL_OUTPUT() DDR_SEL |= (1<<RFXX_SEL)
#define HI_SEL() PORT_SEL|= (1<<RFXX_SEL)
#define LOW_SEL() PORT_SEL&=~(1<<RFXX_SEL)

#define SDI_OUTPUT() DDR_SDI |= (1<<RFXX_SDI)
#define HI_SDI() PORT_SDI|= (1<<RFXX_SDI)
#define LOW_SDI() PORT_SDI&=~(1<<RFXX_SDI)

#define SDO_INPUT() DDR_SDO&= ~(1<<RFXX_SDO)
#define SDO_HI() PIN_SDO&(1<<RFXX_SDO)

#define SCK_OUTPUT() DDR_SCK |= (1<<RFXX_SCK)
#define HI_SCK() PORT_SCK|= (1<<RFXX_SCK)
#define LOW_SCK() PORT_SCK&=~(1<<RFXX_SCK)

#define LED_OUTPUT() DDR_LED |=0x0F
#define LED0_ON() PORT_LED&=~(1<<0)
#define LED0_OFF() PORT_LED|= (1<<0)
#define LED0_TRG()PORT_LED^= (1<<0)

#define LED1_ON() PORT_LED&=~(1<<1)
#define LED1_OFF() PORT_LED|= (1<<1)
#define LED1_TRG() PORT_LED^= (1<<1)

#define LED2_ON() PORT_LED&=~(1<<2)
#define LED2_OFF() PORT_LED|= (1<<2)
#define LED2_TRG() PORT_LED^= (1<<2)

#define LED3_ON() PORT_LED&=~(1<<3)
#define LED3_OFF() PORT_LED|= (1<<3)
#define LED3_TRG() PORT_LED^= (1<<3)

unsigned char RF_RXBUF[22];
void RFXX_PORT_INIT(void){
   HI_SEL();
   HI_SDI();
   LOW_SCK();
   SEL_OUTPUT();
   SDI_OUTPUT();
   SDO_INPUT();
   SCK_OUTPUT();
}
unsigned int RFXX_WRT_CMD(unsigned int aCmd){
   unsigned char i;
   unsigned int temp;
   LOW_SCK();
   LOW_SEL();
   for(i=0;i<16;i++){
      temp<<=1;
      if(SDO_HI()){
         temp|=0x0001;
      }
      LOW_SCK();
      if(aCmd&0x8000){
         HI_SDI();
      }else{
         LOW_SDI();
      }
      HI_SCK();
      aCmd<<=1;
   };
   LOW_SCK();
   HI_SEL();
   return(temp);
}
unsigned char RF01_RDFIFO(void){
   unsigned char i,Result;
   LOW_SCK();
   LOW_SDI();
   LOW_SEL();
   for(i=0;i<16;i++){//skip status bits
      HI_SCK();
      HI_SCK();
      LOW_SCK();
      LOW_SCK();
   }
   Result=0;
   for(i=0;i<8;i++){//read fifo data byte
      Result<<=1;
      if(SDO_HI()){
         Result|=1;
      }
      HI_SCK();
      HI_SCK();
      LOW_SCK();
      LOW_SCK();
   };
   HI_SEL();
   return(Result);
}
void main(void)
{
   unsigned int intI,intJ;
   unsigned char i,j,ChkSum;
   for(intI=0;intI<10000;intI++)for(intJ=0;intJ<123;intJ++);
   RFXX_PORT_INIT();

   RFXX_WRT_CMD(0x0000);
   RFXX_WRT_CMD(0x898A);//433BAND,134kHz
   RFXX_WRT_CMD(0xA640);//434MHz
   RFXX_WRT_CMD(0xC847);//4.8kbps
   RFXX_WRT_CMD(0xC69B);//AFC setting
   RFXX_WRT_CMD(0xC42A);//Clock recovery manual control,Digital filter,DQD=4
   RFXX_WRT_CMD(0xC240);//output 1.66MHz
   RFXX_WRT_CMD(0xC080);
   RFXX_WRT_CMD(0xCE84);//use FIFO
   RFXX_WRT_CMD(0xCE87);
   RFXX_WRT_CMD(0xC081);//OPEN RX
   DDRB|=(1<<RFXX_DATA);
   
   DDRD&=~(1<<2);
   
   LED_OUTPUT();
   
   i=0;
   while(1){
      while(!(PIND&(1<<2))){//polling the nIRQ data
         RF_RXBUF[i++]=RF01_RDFIFO();//read FIFO data
         if(i==18){
            i=0;

            RFXX_WRT_CMD(0xCE84);//reset FIFO for next frame recognition
            RFXX_WRT_CMD(0xCE87);
            ChkSum=0;
            for(j=0;j<16;j++){
               ChkSum+=RF_RXBUF[j]; //calculate checksum
            }
            if(ChkSum==RF_RXBUF[16]){//frame check
               LED0_TRG();//receive indication
            }
         }   
      }
   }
}

Go Up