Tuto. 8 - Microwire Eeprom
PIC tutorial 8 - Microwire Eeprom
Fig. 1 Board 4 with Microwire Eeprom and 8 leds board
Description:
This tutorial covers Microwire communication. It is very close to SPI, but the operations uses different number of bits. We will use the fact that a start bit begins every communication to fit every command in a set of bytes (multiple of 8 bits), which is the only way to be able to use hardware SPI implementation. This means we'll have to prefix the initial byte with a number of bits set to 0 to have the start bit at the right place. The other option is to use bit banging with the proper number of bits, but that would be software emulation. We'll try to stay with hardware implementation when possible. Bit banging implementation is discribed with the graphic LCD library.
You will need a processor board, a power supply, the Microwire Eeprom board and the 8 leds output board.
The boards can be powered by one of the PSU boards (powered from USB port), or between 2.7 to 5V.
Requirements:
Processor boardAny board (board 4 in example)
Extension(s)Microwire Eeprom 93Cx6
8 bits leds
Power supplyPSU 1, 2 or 3. Depends on board used.
LanguageCCS C
ProgrammerPicKIT 2
Program:
#define board_id 1 //* define chip used
#define Chip_93Cx6 9346
#include "93C46_EEPROM.h" // load header file and libraries
BYTE cmpt1, addr;
WORD a;
#int_rtcc
void Timer0Interrupt ( void ) {
if (cmpt1 != 0) cmpt1--;
}
void main() {
boot_up();
Init_SPI(); // Init SPI interface
Init_93Cx6(); // Init memory chip
addr = 5;
a = 0xff55;
write_93Cx6(addr, a); // write 1111 1111 0011 0101 to address 5
a = 0;
setup_timer_0 ( RTCC_DIV_256 | RTCC_8_BIT ); // setup timer 0
enable_interrupts ( INT_RTCC ); // enable Timer0 interrupt
enable_interrupts ( GLOBAL ); // enable all interrupts
cmpt1 = 0;
while (TRUE) {
if (cmpt1 == 0) {
a = read_93Cx6(addr); // read 16 bits at address addr
#if (board_id == 1) | (board_id == 2)
output_a(a&0xff); // output lower byte on port A for board 1 or 2
#else
output_b(a&0xff); // or port B on other boards
#endif
cmpt1=100;
}
}
}
The program defines the processor board used and the type of memory chip fitted on the microwire eeprom board (93C46 in the example). It can be defined as 9356, 9346 and 9306, the 3 chips handled by the library.
We then loads the header file, which load SPI and microwire libraries. The spi library was already covered in tutorial 2.
Once all libraries are loaded, we declare variables to hold the counter for timer 0 interrupts, the data read from the eeprom and the address to work with.
The interrupt for timer 0 is then declared. It just decrements the assigned counter if different than 0.
The processor board, SPI interface and eeprom are then initialised.
The word a (with value 0xff55) is then written to the eeprom at address 5. The 93xx eeprom stores data as 16 bits.
Timer 0 is setup as an 8 bit counter, with a prescaler of 256 and the interrupts are enabled.
The main loop is then entered: we simply check the interrupt counter, and if 0, we read the same address in the eeprom. The lowest 8 bits are sent to a port, where the leds output board will display the byte read. We reset the interrupt counter and loop again.
The header file:
#ifndef __CONFIG_APP_H
#define __CONFIG_APP_H
#include "../lib/Boards/mainboard.c"
#include "../lib/Memory/uWire_EEPROM.c"
#priority RTCC
#endif
It simply loads the processor board and the micowire eeprom libraries. It also set interrupts from rtcc with high priority.
Now the Microwire eeprom 93cx6 library.
#ifndef _MICROWIRE_LIB
#define _MICROWIRE_LIB
#include "../lib/Memory/uWire_EEPROM.h" // load header file
void Init_93Cx6 (void) { // initialise memory chip
output_low(CS_EEPROM); // release chip (chip select signal active high)
output_low(MOSI);
output_low(SCK);
#if (getenv("SPI"))
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_64);
#else
#use spi(DI=MISO, DO=MOSI, CLK=SCK, BITS=8, MODE=0)
#endif
output_high(CS_EEPROM); // memory chip enabled
output_float(MISO);
#if (Chip_EEPROM == 9356)
SPI_out(0x04); // Write enable
SPI_out(0xC0);
#else
SPI_out(0x01); // Write enable
SPI_out(0x30);
#endif
output_low(MOSI); // release chip
output_low(SCK);
output_low(CS_EEPROM);
}
void write_93Cx6(BYTE address, WORD data) { // writes 16 bits at address
output_high(CS_EEPROM);
#if (Chip_EEPROM == 9356)
spi_out(0x05); // send write command
address &= 0x7f; // update address (keep lower 7 bits)
#elif (Chip_EEPROM == 9346)
spi_out(0x01); // send start bit + read command
address &= 0x3f; // update address (keep lower 6 bits)
bit_set(address, 6);
#else spi_out(0x01); // send start bit
address &= 0x0f; // update address (keep lower 6 bits and add write command)
bit_set(address, 6);
#endif
spi_out(address); // send address/command
spi_out16(data); // send data to write as 16 bits
output_low(MOSI);
output_low(CS_EEPROM); // release chip
delay_ms(15); // Write cycle timer
}
WORD read_93Cx6(BYTE address) { // returns 16 bits stored at address
WORD data;
output_high(CS_EEPROM); // enable chip
#if (Chip_EEPROM == 9356)
spi_out(0x0c); // send start bit + read command
address &= 0x7f; // update address (keep lower 7 bits)
#elif (Chip_EEPROM == 9346)
spi_out(0x03); // send start bit + read command
address &= 0x3f; // update address (keep lower 6 bits)
#else
spi_out(0x03); // send start bit + read command
address &= 0x0f; // update address (keep lower 4 bits)
#endif
address<<=1; // shift address 1 bit to accomodate for dummy bit when reading
spi_out(address); // send address
data=SPI_in16(0); // Read 16 bits
output_low(CS_EEPROM); // release chip
return(data);
}
#endif
First we load the header file, which will load the SPI library, as the library will use SPI functions to manage the eeprom.
The functions to manage the memory chip are:
- Init_93Cx6 set up the SPI interface for the microwire chip. The main thing to keep in mind is that the clock needs to be 1 MHz maximum. It also setup the mode for the SPI interface and make sure the chip is write enabled.
- write_93Cx: sends a 16 bits word to the specified address.
- read_93Cx6: reads the 16 bits word from the specified address.
The trick in using hardware SPI interface is to use the fact that the communication always start with a start bit set to 1. We just need to format the string of bits to send so the start, opcode, address and data bits are in the right order. The 1st byte will have the right number of leading bits set to 0 to have the start bit at the right place. Also in the read function, we add a 0 at the end of the address bits to start reading the bits coming out of the chip only after the dummy bit.
The library header file:
#ifndef _SPI_EEPROM_H
#define _SPI_EEPROM_H
#include "../lib/Common/SPI.c" // load SPI generic library
#ifndef CS_EEPROM // CS line for EEPROM
#define CS_EEPROM CS_SPI0
#endif
#ifndef Chip_EEPROM // check a chip is selected. If not default it to 9346
#define Chip_EEPROM 9346 // 9306, 9346 and 9356 are the possible values
#endif
// function prototypes
void Init_93Cx6 (void);
void write_93Cx6(BYTE address, WORD data);
WORD read_93Cx6(BYTE address);
#endif
The header loads the SPI library, defines the CS line used by default if not already defined. CS0 is used by default, so make sure the jumper on the eeprom board is positionned properly. The chip used is then checked, and defined by default to a 93C46.
Compile the project and program the target with a PicKIT 2 programmer for example. Connect the processor board to the Microwire Eeprom board with the SPI bus and the 8 leds output on port B. Make sure the CS jumper on the memory board is setup accordingly with the CS line defined in the program.
Power up the boards.
The chip will be written with the 16 bits word, and then that same address is read and its LSB byte displayed on the leds.
To change chip type, just define Chip_93Cx6 with the desired value (9306, 9346 or 9356) and recompile. The program is then set for that chip.
Files and links:
Tutorial 8 source files.Processor board 4.
Microwire Eeprom board.
8 Leds output board.

