Nokia N85/N86 AMOLED display hacking project AMDF001 / AMDN001

October 9, 2011 Leave a comment

Well, after a while , I’ve found that E51-like LCD displays are barely readable in sunlight, which renders them unusable in outdoor conditions. So, after deep search, I’ve found nice and cheap potential solution : N85/N86 display.
It is active matrix OLED screen (AMOLED) 320×240, 2.58″, manufactured by (I believe) Samsung SMD (www.samsungsmd.com). There is markup on this OLED : AMDF001 AMDN001 (see below …) (which is probably FPCB model type (flexible printed circuit)). Other ID’s are : 4850084 (which is probably manufacturer ID code (see google)), MP1.0 which denotes interface protocol? (MeSSI ?)

Display have FPC 24-pin connector widely used by Nokia (same as E51), but different pinout is used – see N85/N86 schematic wiring diagram -> google it, download level 1/2 manuals.

Nokia uses codename Falcon for this display -> no effect after google.

What I’ve done :
1. As microcontroller I used PIC32MX (340F512H), communicating with PC via UART
2. I’ve created 2 prototype boards :
a) level shifter board (3.3V -> 1.8V) using 74LVC4245A (2x) one for databus D0..7, one for controls (RDX,WRX,RESX,DCX)
b) OLED display power supply (MC1727-500 & MAX889) generating -4.9V & +4.6V for ELVSS & ELVDD respectively.
3. I’ve dismounted 24 pin connector from display’s FPCB and soldered 24 wires to that connector’s pads (I’ve used old 80-pin ATA cable as a small wire donor)

After battle with my solder gun I finally ended up with working prototype, with NULL knowledge of protocol…

Digging the Web for similar display’s datasheets I’ve found that similar displays controllers using similar interface protocols, of course AMDF001 is using Intel 80 8-bit bus, just like E51 module.
It seems that it is using such protocol :

1. with DCX=0 write register addr (D0..7 => reg index)
2. with DCX=1 write data to that register … 8-bit or 16-bit??? (double 8bit transfers?)

After brute-forcing this module I’ve found that it is responding to commands (screen blinks, fades in/out, eventually even GRAM memory contents showed up on screen, nice)

Now it is long road to descramble the protocol & register locations…

Or maybe someone has something to say in this topic ???
Any help appreciated!

Update #1 : After days of digging the net searching for possible driver IC that drives this amoled, I’ve found that:
1) probably I have problem with connection bus (amoled seems to respond randomly to sent commands)
2) amoled is responding only when (sic!) LVC4245 is driven reversed (pic<-amoled) on data bus… strange..
3) I personnaly think that IC might be LD9014 from LDT,inc.
4) I really don't think it is S6E63D6X, just because of 262K color depth instead of proclaimed 16.7M for this amoled

Update #2 : Shame on me! These modules I got aren’t AMOLEDs… They turn out to be cheap chinese fakes – LCDs, looking like AMOLED, but they’re not.
Waiting for new delivery, hoping for getting real AMOLED now for n85/86.
Bloody differences ? Here you’ve got :
1) Shorted pins 11 & 12 (EL_ON VIO), gives constant 1.8V on EL_ON…
2) There is small BGA packaged IC on the FPCB just below the screen ( on the back side) – it is probably dc-dc charge pump for LED backlight (very smartly hid below the screen), original AMOLED has only some discrete smd parts on FPCB…
3) real AMOLED has MP2.1 protocol designation & AMS258DN01 module type (driver IC still unknown)

Update #3 : Module marked AMDF001A is an ordinary TFT module compatible with MP1.0 protocol, just like E51 module. Only pinout & backlight driving are different.
Still waiting for AMDN001 modules (which should be amoleds)

Advertisements
Categories: LCD, PIC32, Project Tags: , , , ,

Custom controls design & testing…

For a former Delphi-ist like me, creating custom components was almost an everyday routine, but after switching to more modern & versatile enviroments like C# (VS2010) I’ve found myself lost in the docs & lack of knowledge about such important thing.

However, things are easier than they appear to be.
There is one strange dead-end, called User Controls – well, it is nothing else but a control made of other controls – it is group of controls compiled under one typename…
To create & test your own custom control, you should extend already existing class (like System.Windows.Forms.Control or System.Windows.Forms.Button… etc.)

Suppose, you’re working on an application, and you wan’t to use a new control (e.g. slightly modified MaskedTextBox), follow this route :
1. In your app solution create another class (Add… / Class, Shift+Alt+C)
2. Name it as you want, like MyMaskEdit.cs
3. use your app namespace, or another else (remember to add appropriate usings
4. change the default declaration of your newly created class to something like :


namespace A
{
namespace B
{
[System.ComponentModel.DefaultBindingProperty("Time")]
public class DBTimeEdit : System.Windows.Forms.MaskedTextBox
{
...
}
}
}

Categories: C#

Project attempt: Pulseoximeter

December 19, 2010 1 comment

Source :
http://www.oximeter.org/PulseOx/principles.htm
http://www.edaboard.com/attachments/24135d1178378436-cc2004-12_2018-pdf
http://www.edaboard.com/attachments/24304d1179237986-ti_app__notes_for_pulse_oximetry_1486-pdf
http://www.circuitcellar.com/microchip2007/winners/DE/abstracts/MT2278_Abstract.pdf
http://www.cypress.com/?rID=2696

Did some basic research…

Description of operation :
The device uses 2 LEDs, one bright red (about 640nm) and one IR (about 910nm). These LEDs transflects the finger (or other suitable tissue), and the light gets into sensor.
Sensor can be a photodiode (such as BPW34), or Light-to-Frequency converter (like TSL230…)
Because I cannot obtain TSLxxx (the easier solution), I’m forced to use photodiode BPW34.
Using TSLxxx leads to “almost” pure digital solution, simply introducing TSL’s output into InputCapture module of MCU, counting pulses, some digital filtering, AC part extraction & showing up results.
Photodiode is a bit trickier… Signal is very small, I have to use instrumentation amplifier with very low drift as an input opamp (transimpedance approach), filter DC part of the signal, extract the “pulse” wave, amplify it and then sample via ADC (then filtering, calculations & ->LCD).
There are many analog part solutions to this problem, but I didn’t find the one I could repeat.
(Cypress’ version is very sophisticated, but I cannot find any “cheap” PSoC chip near my localization, combining it with need for new programmers/debuggers rendering it very far from acceptable…)

Do you have any ideas, how to design analog part of this project ?

I2C EEPROM & PIC32

December 9, 2010 1 comment

Few useful examples, how to force HW I2C module of PIC32MX to collaborate with I2C EEPROM chip, like Microchip’s 24LC1025.

I2C Module Initialization

void eepromInit(void)
{
 I2CConfigure(EE_I2C, I2C_ENABLE_SLAVE_CLOCK_STRETCHING | I2C_ENABLE_HIGH_SPEED);
 I2CSetFrequency(EE_I2C, GetPeripheralClock(),400000);
 I2CEnable(EE_I2C, TRUE);
}

For single master-slave enviroment, you can omit I2C_ENABLE_SLAVE_CLOCK_STRETCHING config word.

Reading from EEPROM.

void eepromRead(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 // Start
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);        // Write control byte
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 MasterWriteI2C2(ee_addr >> 8);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 RestartI2C2();
 IdleI2C2();
 MasterWriteI2C2(EE_ADDR | 1);        // Read command
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 while (len)
 { 
 I2C2CONbits.RCEN = 1;
 while(!DataRdyI2C2());
 *buf = I2C2RCV;
 buf++;
 len--;
 if (len)
 {
 // ACK the slave
 I2C2CONbits.ACKDT = 0;
 I2C2CONbits.ACKEN = 1;
 } 
 else
 {
 // NACK the slave
 I2C2CONbits.ACKDT = 1;
 I2C2CONbits.ACKEN = 1;
 } 
 while(I2C2CONbits.ACKEN == 1);    /* Wait till ACK/NACK sequence is over */
 } 
 StopI2C2();
 IdleI2C2();
}

where EE_ADDR is #defined as 0xA0 , corresponding to EEPROM’s control word.
This function has limited functionality – it can only read first 0xFFFF bytes of data from EEPROM – no code provided to set B0 bit in config word (see datasheet).

Writing to EEPROM.

void eepromWritePage(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 // Start
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);        // Write control byte
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr >> 8);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 while (len)
 {    
 MasterWriteI2C2(*buf++);
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 len--;
 }    
 StopI2C2();
 IdleI2C2();

 // Do acknowledge poll (indicating, that eeprom has completed flashing our bytes
 while(1) {
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);    // Call the eeprom
 IdleI2C2();

 if (I2C2STATbits.ACKSTAT==0) break;
 StopI2C2();
 IdleI2C2();
 }

 StopI2C2();
 IdleI2C2();
}    

void eepromWrite(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 int bytes_to_write;
 while (len)
 {
 bytes_to_write = 0x80;    // default xx1025 pagesize
 if (len<bytes_to_write) bytes_to_write = len;
 eepromWritePage(ee_addr, buf, bytes_to_write);
 len-=bytes_to_write;
 buf+=bytes_to_write;
 ee_addr+=bytes_to_write;
 }    
}

because of limited amount of data for single write command (page size of this eeprom is 128 bytes), you should call eepromWrite(…) function, which can handle writes in 0x0000-0xffff addresses in eeprom space. (the same limitation with B0 bit as for eepromRead() func).

Have fun.

RFM22 PIC32MX library and code example

October 12, 2010 6 comments

Here you go with the library :
RFM22.ZIP
Consider it as a very young release, highly uncommented and not optimized.

It works with PIC32MX MCUs. SPI is currently emulated in software, because for unknown reason, the HW code doesn’t work.

To use library, you should #include "rfm22.h" in your code, and add rfm22.c to your project.

You should also look at the beginning of rfm22.h.

#ifdef __PIC32MX
 #define RFM22_nIRQ     		_RD9
 #define RFM22_nRES			_LATB4
 #define RFM22_nSEL			_LATG9
 #define RFM22_SCK			_LATG6
 #define RFM22_SDO			_LATG8
 #define RFM22_SDI			_RG7
 #define RFM22_nIRQ_TRIS     	_TRISD9
 #define RFM22_nRES_TRIS		_TRISB4
 #define RFM22_nSEL_TRIS 	        _TRISG9
 #define RFM22_SCK_TRIS 		_TRISG6
 #define RFM22_SDO_TRIS 		_TRISG8
 #define RFM22_SDI_TRIS 		_TRISG7
 // external interrupt with nIRQ line hooked
 #define RFM22_int_ie		IEC0bits.INT2IE
 #define RFM22_int_flag		IFS0bits.INT2IF
#endif
// define below to use SW emulated SPI
#define USE_SW_SPI

You should tune it to your hardware routing.

It is nice to wait for some time after power-up of your MCU, so after stabilizing your device you should initialize RFM22 :

void init_system()
{
 // disable JTAG port
 DDPCONbits.JTAGEN = 0;
 // config wait-states &amp; cache
 SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
 }

int main()
{
 DelayUs(100000);
 init_system();
 AD1PCFG = 0xffff;
 init_radio();
 // Turn on the interrupts
 INTEnableSystemMultiVectoredInt();
 ...

where init_radio() is defined with :

void init_radio()
{
// FIRST! enable INT2
INTCONbits.INT2EP = 0;    // INT2 edge -&gt; int request at FALLING
IPC2bits.INT2IP = 2;
IPC2bits.INT2IS = 3;
IFS0bits.INT2IF = 0;    // clear flag
IEC0bits.INT2IE = 0;    // enable int | CURRENTLY DISABLED in LIBRARY !!!
// THEN! initialize rfm22 !!!
_TRISB5 = 1;
_TRISD9 = 1;
rfm22_Init(868, GetPeripheralClock(), 5000000);
rfm22_go_rx();
}

_TRISB5 and _TRISD9 routes nIRQ signal in my project, you may ommit this lines.
GetPeripheralClock() is a macro defining PB_CLK of your PIC32 in [Hz]. 868 is a literal indicating working frequency of RFM22 module.
rfm22_Init(…) initializes SPI, performs SW_RESET of RFM22 and sends basic configuration of RFM22 registers.
rfm22_go_rx() switches RFM22 module into RX mode.

In your main loop you should poll nIRQ line status :

while(1)
{
 if (!RFM22_nIRQ)
 rfm22_Handle_IRQ();
 ...

There is nothing wrong with INT2 external interrupt attempt, but be aware of proper timings and interrupt service routine execution length. If your main loop is executed fast enough, there is no need to use an external interrupt handler, and your code would be level-related-IRQ rather than egde-related-IRQ using INT2.

For example, INT2 handler should looks like :

void __ISR(_EXTERNAL_2_VECTOR, ipl2) INT2Handler(void)
{
rfm22_Handle_IRQ();
IFS0bits.INT2IF = 0;
}

Remember to set proper ipl in this ISR function invocation, according to defined interrupt priority level for INT2.

Currently, rfm22_Handle_IRQ() is defined with following code :

void rfm22_Handle_IRQ()
{
	rfm22_ReadStatus();
	
	// check POR condition
	if (rfm22.isr2.b.IPOR)
	{
		rfm22_go_ready();
	}
	
	if (rfm22.state == RFM22_TX)
	{
		if (rfm22.isr1.b.IPKS)
		{
			// packet sent, RF module went back to READY
			rfm22.tx_state = RFM22_TX_COMPLETE;			
		}	
	}
	
	if (rfm22.state == RFM22_RX)
	{
		if (rfm22.isr1.b.IPKV)
		{
			// received valid packet
			// get the RX FIFO
			int i;
			
			int len = rfm22_Read(0x4B);	// get the received packet length
			
			rfm22_StartBurst(0x7f,0);	// read FIFO in burst read mode
			for (i=0;i<len;i++)
			{
				rfm_rx_buffer[i] = rfm22_BurstRead();
			}	
			rfm22_EndBurst();		
			rfm22.rx_state = RFM22_RX_COMPLETE;
		}			
		
		if (rfm22.isr1.b.ICRC)
		{
			// CRC-error occured - restart receiving
			rfm22_ResetRxFifo();
			rfm22_go_rx();	
		}	
		
		if (rfm22.isr2.b.IPVD)
		{
			rfm22_last_rssi = rfm22_Read(0x26);	// get RSSI
		}	
	}			
}	

I think it is understandable with a little effort.
Code asserts specific state machines according to RFM22 interrupts, e.g. sets RFM22_TX_COMPLETE state of library TX state machine, when packet sent interrupt flag was set.
User may poll for this state in main loop.
RFM22_RX_COMPLETE indicates that rfm_rx_buffer[] contains downloaded data from recently received packet. User should poll for this flag, and perform specific action, e.g. :

while (1) {
...
if (rfm22.rx_state == RFM22_RX_COMPLETE)
{
// process incoming data
rfm22.rx_state = RFM22_RX_IDLE;     // indicate, that packet has been processed
ackbuf[0] = 0xAC;
ackbuf[1] = rfm22_last_rssi;    // RSSI
rfm22_tx_buf_block((uchar*)&amp;ackbuf[0],2);
rfm22_go_rx();
}

UPDATE 07.02.2011: Newer version of RFM22 lib is just uploaded and available under link at the top of this post. Same restrictions about using it : IT IS A DRAFT. IT WORKS… SOMETIMES… 🙂 There are many holes in the code and lacks of documentation, but I really don’t have time to clean up this mess. Maybe someday.

RFM22 Programming tutorial – PART #2

October 12, 2010 64 comments

RFM22 internal registers
When you look into datasheets, you may feel a little bit lost 🙂
Yeah, there are near 127 registers in this little module, but many of them are set-and-forget ones.
Moreover, there are MSExcel spreadsheet calculators, providing you with set of calculated values for
your RFM22 module. You only have to enter desired transmittion parameters.
Look at : Calculator for Vx silicon revision
Calculator for A0 silicon revision
Calculator for B1 silicon revision

To determine your RFM22 chip’s silicon revision, read register at 0x01.

More important registers are (these you should become familiar with, these needs frequently changes during operation):

  • 0x02 – Device status register
  • 0x03 – Interrupt flags register #1
  • 0x04 – Interrupt flags register #2
  • 0x05 – Interrupt enable register #1
  • 0x06 – Interrupt enable register #2
  • 0x07 – Mode of operation register #1
  • 0x08 – Mode of operation register #2
  • 0x72 – Frequency deviation / AFC limiter
  • 0x02 – Device status register

  • ffovfl – FIFO overflow, you’ll see this, when you try to upload more than 64 bytes into TX FIFO, or module receives more than 64 bytes or you didn’t downloaded RX FIFO in right time.
  • ffunfl – FIFO underflow, set, when module is trying to send more data than is in its TX FIFO (eg. you’ve set longer packet than you uploaded into TX FIFO)
  • rxffem – RX FIFO empty – module should awake with this bit set, self-explanatory, I think.
  • headerr – Header error – indicates corrupted header of recently received packet
  • freqerr – Frequency Set error – you’ve tried to tune RFM outside its operating range (240-930 MHz).
  • lockdet – Synthesizer Lock detected – RF synthesizer is working ok and locked to specified frequency… rather informative/diagnostic than useful in everyday work 🙂
  • cps[1:0] – Chip Power State – indicates whether module is IDLE (00), RX (01) or TX (10)
  • Notes: Normally, there is a little need to read this register in FIFO Packet Handler mode. Frankly, I don’t pay attention to this register at all, using FIFO+PH.

    0x03 – Interrupt flags register #1
    0x04 – Interrupt flags register #2
    These registers are quite good described in the datasheet, all flags are more or less self-explanatory.
    Reading these registers clears indicated interrupt request and releases nIRQ line of RFM22.
    You should read them after nIRQ goes LOW.
    if (!nIRQ)
    rfm22_Handle_IRQ();

    0x05 – Interrupt enable register #1
    0x06 – Interrupt enable register #2
    When specific bit in these registers is SET, then asserting particular flag in 0x03/0x04 also drives nIRQ LOW.
    You should set ONLY these interrupts enabled, you’re interested in during current mode of operation, e.g. you should enable PKTSENT interrupt before entering TX mode – when nIRQ goes LOW you would know that packet has been sent, and you don’t need to check all interrupt flags. That approach would simplify your code to maximum extent.

    0x07 – Mode of operation register #1

    This is the most important register of the module.

  • swres – soft reset request – writing 1 to this bit would reset RFM22 to default state. You should do this after powerup of your system.
  • txon – TX mode ON – manual start of the transmittion. You should set this bit, after filling TX FIFO with data you want to send. Module will start transmittion and asserts ipktsent flag after sending whole payload. After transmittion module will fall into IDLE mode.
  • rxon – RX mode ON – manual start of reception. Setting this bit to 1 simply starts reception. RFM22 would wait for packet, receives it, checks its integrity and checksum and asserts corresponding flags (see 0x03,0x04 registers) during and after reception :
    ipreaval – valid preamble detected – asserted during reception of valid preamble. THIS IS THE MOMENT when you should save RSSI variable (content of 0x26 register) – that would indicates signal strength of transmittion.
    iswdet – synch word detected & match – module would assert this bit, when valid synch words are detected during reception of current packet, rather informative…
    icrerror – CRC error – received packet is corrupted – CRC calculated & received don’t match. You should respond to this IRQ with restarting RX mode (reset RX FIFO & set RX mode ON).
    ipkvalid – Valid packet received – this is the most wanted flag during reception – indicates that RX FIFO contains healthy data, just as you sent them on the TX side.
  • pllon – PLL ON during IDLE – leaves PLL working during IDLE mode – results in faster transitions between IDLE->RX and IDLE->TX modes. (PLL is tuning up for about 1 ms). With xton set would indicate TUNE-IDLE mode (higher current consumption ~9.5mA)
  • xton – XTAL ON – setting only this bit in this register would indicate READY-IDLE mode (low current consumption <1mA)
  • 0x08 – Mode of operation register #2

    This register controls mainly RX/TX FIFO buffers. Other settings are less important.

  • rxmpk – RX multiple packet mode – Once rxon set, the reception would continue, and RX FIFO would be filled subsequently after each valid packet reception. You can see ffovfl flag here. If rxmpk is cleared, RFM22 would fall into IDLE mode after reception of packet (either valid or invalid !!!)
  • autotx – Automatic TX mode – when set, module would enter transmittion mode each time TX FIFO is filled up to almost-full-condition. With this bit cleared, RFM22 would wait for txon bit set in 0x07 reg.
  • ffclrrx – RX FIFO Clear – to reset RX FIFO, you should write 1 and subsequent 0 to this bit. See code : send(0x08,0x02); send(0x08,0x00);
  • ffclrtx – TX FIFO Clear – accordingly, writing 1 and then 0 to this location would reset TX FIFO buffer and pointer.
  • 0x72 – Frequency deviation / AFC limiter
    Why this magic register is important? It depends on silicon revision of your RFM22 chip. When it is V2 (register 0x01 == 0x02) it has double function. In RX MODE it acts as Automatic Frequency Control Limiter – you should set this reg BEFORE entering RX MODE, according to calculated value. In TX MODE this register acts as Frequency Deviation register. You should write desired frequency deviation value BEFORE entering TX MODE.

    RFM22/23 Programming tutorial – PART #1

    October 11, 2010 1 comment

    Because there is a serious lack of information over the internet about programming RFM22 modules, here you’ve a quick tutorial.

    Here you go with the connections :

    Fig.1. Schematic of RFM22 connections

    Description of Fig.1. :

  • SDN pin of RFM22 is tied LOW to GND – forget about very-low-power shutdown mode, if you need it – modify the schematic (connect it to pin of your MCU)
  • GPIO_0 is programmed to drive RX_ANT input – you can save 1 pin of your MCU here
  • GPIO_1 is programmed to drive TX_ANT input – another 1 pin saved
  • GPIO_2 is CLK_OUT at power on condition of RFM22, you can use it as clock source to your MCU
  • There are some bypass caps – it is nice to solder them, anyway 🙂
  • PAY ATTENTION to SPI wiring… (SDI/SDO lines must be crossed 🙂 )
  • Power the whole thing from 3.3V rail
  • I’m using PIC32MX MCU, but any should work. If your MCU is 5V powered, you must provide some level shifters on SPI lines, but nowadays I believe that it is easier to do the whole thing on 3V3 MCU & stuff than wasting mcu pins & time & pcb space with 74lvc4245…

    Philosophy of operation
    RFM22 may be used in many different modes. The one I would describe is FIFO mode with Packet Handling. It is the easiest mode to implement, RFM22 is doing the most of the job, MCU has hands free most of the time.
    FIFO mode with Packet Handling means, that during transmition, MCU is uploading data into radio’s FIFO, RFM is encapsulating user’s data into packet structure and sends it over RF using correct timing, defined in setup step.
    During reception, RFM is detecting preamble, synch words, packet headers (optional), receiving subsequent data bytes into Rx FIFO and doing CRC check over the packet contents (data only or whole packet). If CRC is OK, then RFM is asserting an interrupt request.

    Packet structure of RFM22 :
    [PREAMBLE][SYNCWORD][HEADER][PKTLEN][DATA 0…n][CRC]

    Preamble consists of 1-512 bytes (user configurable count) of 0xAA (10101010b)
    Synch word usually equates to 0x2DD4, but may be configured to desired values
    Header consists of 0-4 bytes (user configurable count & content), consider it as a IP address of packet – receiving side may compare it with predefined variables to determine destination of received packet.
    PktLen is 1 byte if variable packet lengths are in option, it may be ommitted when RFMs are configured to deal with fixed length packets.
    CRC is checksum calculated over data or whole packet structure, usign one of four predefined polynominals (all in hardware of RFM22).

    SPI interface
    SPI interface is using 8 bit transfers. First transfer of each command contains address of RFM22 register and operation bit (Read/Write). Subsequent transfers contains data to be written into register(s), or readings from register(s).
    Each transfer may consist of single write/read command, or may be a burst write/read.

    1. Single write command :
    nSEL=0 | [1][REG_ADDR 0..0x7F] | [DATA_BYTE]sdo | nSEL=1

    2. Single read command :
    nSEL=0 | [0][REG_ADDR 0..0x7F] | [REG_VAL]sdi | nSEL=1

    3. Burst write command :
    nSEL=0 | [1][REG_ADDR 0..0x7F] | [DATA_BYTE0]sdo | [DATA_BYTE1]sdo | [DATA_BYTEn]sdo |nSEL=1
    NOTE : Consecutive bytes are written to addresses starting at REG_ADDR, incrementing after each byte, unless REG_ADDR is 0x7F.
    If REG_ADDR is 0x7F (FIFO gateway), incrementing is disabled, and whole transfer is going through 0x7F register – it allows to burst read/write FIFO in single block.

    4. Burst read command :
    nSEL=0 | [0][REG_ADDR 0..0x7F] | [REG_VAL0]sdi | [REG_VAL1]sdi | [REG_VALn]sdi |nSEL=1
    The same notes as for burst write applies to burst read command.

    Example of setting READY mode of operation :
    nSEL=0 | 0x87 | 0x01 | nSEL=1
    It means, that write (MSB bit (0x80) is set in address) is performed to 0x07 register (mode of operation), with value 0x01 (IDLE, READY).

    RFM22 internal registers
    When you look into datasheets, you may feel a little bit lost 🙂
    Yeah, there are near 127 registers in this little module, but many of them are set-and-forget ones.
    Moreover, there are MSExcel spreadsheet calculators, providing you with set of calculated values for
    your RFM22 module. You only have to enter desired transmittion parameters.

    More important registers are :

  • 0x02 – Device status register
  • 0x03 – Interrupt flags register 1
  • 0x04 – Interrupt flags register 2
  • 0x05 – Interrupt enable register 1
  • 0x06 – Interrupt enable register 2
  • 0x07 – Mode of operation register
  • 0x08 – FIFO control register
  • more coming soon… need some sleep 🙂

    —————————————————————————————————

    RFM22 interface library v.0.0.1 pre-alpha version 🙂
    http://rapidshare.com/files/424493489/RFM22.ZIP
    Tested with PIC32MXs, 20kbauds configured, 868MHz operation, interrupt operation (INT2) currently switched off.