Archive for the ‘PIC32’ Category

Nokia N85 / N86 AMOLED interfacing (& surprise) …

October 23, 2011 27 comments

Have a look at it :

Notice that it is an AMDN001 marked module (which is, in fact, real AMOLED from N85/86).

Now the surprise : it works with the command set known from E51/6500c LCDs…
Yes! No changes, just solder the wires, build +5V/-5V DC-DC converter & Voilla…

The DC-DC can looks like : (I’ve managed to homemade it on 2.5×3.0cm single sided PCB).

TPS65136 is available in QFN package only, its tricky to solder it at home, but having any hot-air & flux should do the trick. Remember that thermal pad should be GND-ed (& soldered too, of course).

UPDATE #1: There is one error in schematic – the L1 inductor should be 2.2uH or 4.7uH instead of 10mH (ekhm… “hardly available” 🙂 ).
To successfully drive this AMOLED it is sufficient to have such wiring : D0-D7, RES, WR, DC for control, and power sources : 3V3, ELVDD, ELVSS.
There is no need for 1V8 and level shifters like LVC4245. Driving VIO pin (12) with 3.3V voltage we’re getting whole interface bus working at 3.3V. (Don’t know exact timing impact with such voltage change, but it works at full speed achievable with PIC32MX parallel master port)

Nokia Display Modules Hacking Platform :)

October 18, 2011 4 comments

NDMHP in short 🙂 easy, huh ?

Today, I’ve got some hardware & software to share – In the meantime I’ve created some nice piece of hardware, and I named it as you can see above.
It consists of :
1). PIC32MX340F512H prototype board (PIC & necessary components to run it)
2). Voltage-level shifter based on LVC4245
3). Adapter board with voltage inverter & stabilizer (~+5V/-5V for amoled display) – not recommended to use, try to get TPS65136 ( instead.
4). Power source with different voltages (1.8V, 2.5V, 3.3V, 5.0V, 12.0V)

Here comes some pictures of this crap :

Fig.1. PIC32MX proto-board

Fig.2. Level-shifter & n86 adapter board with DC-DC inverter & stabilizer

Fig.3. Photo of working AMDF001 connected to that crap above.

Here comes some schematics :
1) I would not provide you with proto-board of PIC32MX, because it is so self understandable, that it would be a shame to do this…
2) Level-shifter & n86 adapter board :

And some code, (very dirty but working…) :

Some description :
PC is connected to PIC32 via RS232 @ 57600 bauds (MAX3232 not visible – mounted inside COM1 plug, powered from PIC32 proto-board). PC is running C# program – win_amo_hack, PIC32 is flashed with included code (n86_amoled_hack).
Communication protocol PCPIC is described below :
– commands are sent as text strings
– commands :
a) ‘r’ – reset (assert RESX line low for 5ms & release high)
b) ‘C’ – pull chip select low (CSX=LOW)
c) ‘c’ – release chip select high (CSX=HIGH)
d) ‘i[xx]’ – write index register/execute command simple command (DCX=LOW, perform write of hexadecimal number [xx] via ParallelMasterPort, eg. “i29” – send DISP_ON command on MP1.0 protocol
e) ‘d[xx]’ – write single byte of data (DCX=HIGH, perform write of hex [xx] via PMP, eg. “d00” – send 0x00 to LCD)
f) ‘t’ – return tearing line status (returns t00 or t01 according to TE line level)
g) ‘g’ – read register or data (DCX=HIGH & perform read via PMP)

“i01i11i29” – this string will initialize MP1.0 display (reset, sleep-out, display-on)
“i2cd00d11d22” – this string will send one pixel data (0x2c – GRAM_WRITE), color 0x001122

Win_amo_hack has also ability of execution of Lua scripts.
It defines two functions : amoSend & amoTear. First one takes single string argument & sends that string to PIC32. Second one returns TE line status as a byte.

Sample Lua script :

for y=0,319 do
for x=0,239 do

Well, that’s basically it.
This platform is quite powerfull and can be used to hack multiple types of LCDs, as long as LCD is interfacing via Intel-80 parallel bus.

Have fun.

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 ( 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)

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

Project attempt: Pulseoximeter

December 19, 2010 1 comment

Source :

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 ?


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)
 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

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

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

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

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

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

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

 while (len)
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

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

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

 if (I2C2STATbits.ACKSTAT==0) break;


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);

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 :
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
// 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
 // config wait-states &amp; cache

int main()
 AD1PCFG = 0xffff;
 // Turn on the interrupts

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);

_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 :

 if (!RFM22_nIRQ)

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)
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()
	// check POR condition
	if (rfm22.isr2.b.IPOR)
	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.rx_state = RFM22_RX_COMPLETE;
		if (rfm22.isr1.b.ICRC)
			// CRC-error occured - restart receiving
		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

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)

    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.