Skip to content

Instantly share code, notes, and snippets.

@monsonite
Created June 9, 2011 13:06
Show Gist options
  • Save monsonite/1016694 to your computer and use it in GitHub Desktop.
Save monsonite/1016694 to your computer and use it in GitHub Desktop.
// File Name : c_msp_uni_05.c
// UNIO_memory , MSP430 family , C language , bit-bang method.
// Dependencies : msp430x12xx.h
// Processor : MSP430F1232
// Hardware : MicroChip's UNIO EEPROM = 11XXX on Softbaugh EVB .
// Debug Module : MSP-FET430UIF - Texas Instruments
// I.D.E. : IAR
// Company : MicroChip Technology , Inc.
// Author : Alexandru Valeanu
//...........................................................................
// SOFTWARE LICENSE AGREEMENT
//...........................................................................
// "Microchip Technology Inc. (“Microchip”) licenses this software to you
// solely for use with Microchip Serial EEPROM products.
// The software is owned by Microchip and/or its licensors, and is protected
// under applicable copyright laws. All rights reserved.
// SOFTWARE IS PROVIDED “AS IS.” MICROCHIP AND ITS LICENSOR EXPRESSLY
// DISCLAIM ANY WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE,OR NON-INFRINGEMENT. IN NO EVENT SHALL MICROCHIP
// AND ITS LICENSORS BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
// CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT,
// COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY
// CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
// THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS."
//***************************************************************************
// History : V1.0 - Initial Release
//...........................................................................
// File Description : This is the file for the AN1186
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// HARDWARE CONDITIONS
// The 4 onboard LEDs display success & errror messages.
// In order to perform all of these, they were wired as below :
// P1.3 - D4 , P1.2 - D3 , P1.1 - D2 , P1.0 - D1 .
// The list of error messages is presented in the 'main' function.
// ..........................................................................
// The microcontroller is powered by the internal RC oscillator.
// In order to increase the communication speed, the micro was overclocked
// at a 10Mhz rate ( the datasheet of the MCU doesn't recommend to use
// a higher rate then 8 Mhz ). If a 8Mhz clock speed is desired, to obtain
// the necessary delays, delay functions must be changed accordingly .
// ( the initialization of the oscillator, too ).
// The RC oscillator is used in conjunction with an external resistor :
// R29 (on the E.V.B.) = 100K. It will also decrease the temperature
// drift, as described in the datasheet of the micro.
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
#include <msp430x12x2.h>
//.............................................................................
// GLOBAL CONSTANTS
//.............................................................................
#define DEVADR 0xa0 // slave address
#define START 0x55 // start header
#define READ 0x03 // READ instruction
#define CRRD 0x06 // READ from crt address instruction
#define WRITE 0x6c // WRITE instruction
#define WREN 0x96 // WRITE ENABLE instruction
#define WRDI 0x91 // WRITE DISABLE instruction
#define RDSR 0x05 // READ STATUS register instruction
#define WRSR 0x6e // WRITE STATUS REGISTER instruction
#define ERAL 0x6d // ERASE entire array instruction
#define SETAL 0x67 // SET entire array instruction
#define NOPROT 0x00 // disable all write protections
#define SCIO 0x01 // SCIO = P3.0
#define STRSZ 0x10 // size of string = 16 bytes
#define timeout 0x14 // timeout at sampling SAK/NOSAK
//.............................................................................
// Timer based delays are more accurate, accordingly, a higher communication
// speed was obtained through this method. As an alternative, instructions
// based delays are presented below, too.
//.............................................................................
#define QBT 0xa0 // quarter bit(timer) --> 12 Khz
// #define QBT 0x90
// #define QBT 0x80
// #define QBT 0x70
// #define QBT 0x60 // quarter bit(timer) --> 25 Khz
// #define QBT 0x50
// #define QBT 0x40 // 32Khz
//.............................................................................
// #define QBT 0x3c // 35khz
// #define QBT 0x3a // 37khz
// #define QBT 0x38 // 38khz
// #define QBT 0x34 // 40khz
// #define QBT 0x32 // 42khz
//.............................................................................
// #define QBT 0x30 // 44khz
//.............................................................................
// #define QBT 0x2e // 45Khz
// #define QBT 0x2c // 47khz
// #define QBT 0x2a // 50khz
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define QBI 0x20 // quarter bit(instr) (32:2us)=16us MAX
// #define QBI 0x12 // quarter bit(instr) (18:2us)=09us MED
// #define QBI 0x10 // 16:2us = 08us / speed = 23Khz
// #define QBI 0x0d // 14:2us = 07us / speed = 29Khz
// #define QBI 0x0c // 12:2us = 06us / speed = 32Khz
//..............................................................................
// #define QBI 0x0b // 11:2us = 5.5us / speed = 33khz
//..............................................................................
// #define QBI 0x0a // 10:2us = 05us / speed = 37Khz
// #define QBI 0x09 // 09:2us =4.5us / speed = 42Khz
// #define QBI 0x08 // quarter bit(instr) (08:2us)=04us
// #define QBI 0x05 // quarter bit(instr) (05:2us)=02us
// #define QBI 0x04 //
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// GLOBAL VARIABLES
//.............................................................................
unsigned char err_cnt ; // error counter
unsigned char eep_buf ; // eeprom's data buffer
unsigned int tqb ; // calculated externally and loaded in
// timer_A as quarter bit
unsigned int thb ; // calculated externally and loaded in
// timer_A as half bit
unsigned int iqb ; // quarter bit through instructions
unsigned int ihb ; // half bit through instructions
unsigned char load[STRSZ] ; // global string for "copystr" function
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// FUNCTIONS PROTOTYPES
//..............................................................................
void ini_wdt(void);void ini_rosc(void);void ini_gpio(void);void ini_tim(void);
void mak(void);void nomak(void);void sak(void);void sakq(void);void nosak(void);
void uni_wr(void);unsigned char uni_rdq(void);void uni_wrmns(void);
void uni_wrms(unsigned char ms);void uni_wrnms(unsigned char nms);
void uni_head(void) ; void uni_head2(void) ;
void uni_cmnd(unsigned char cmnd) ; void uni_cmnd2(unsigned char cmnd) ;
void uni_eral(void);void uni_eral2(void);void uni_setal(void);void uni_setal2(void);
void uni_wrsr(unsigned char stat) ; void ini_unio(void) ; void uni_wippol(void);
unsigned char uni_rdsr(void) ;
void uni_wrbyte(unsigned int eep_adr,unsigned char eep_data);
void uni_rdbyte(unsigned int eep_adr,unsigned char *dst);
void uni_crrdbyte(unsigned char *dst);
void uni_wrstr(unsigned char *source,unsigned int eep_adr,unsigned char lofsstr);
void uni_rdstr(unsigned char *dest,unsigned int eep_adr,unsigned char lofdstr);
void uni_crrdstr(unsigned char *dest,unsigned char lofdstr);
void dltim(unsigned int steps); void dlins(unsigned int steps);
void calcdly(void);
void dlthb(void);void dltqb(void);void dlihb(void);void dliqb(void);
void dlythdr(void);void dlytss(void);void dlystby(void);void dly5ms(void);
void dly250ms(void);void dly1s(void);void ferror(void);
void copystr(unsigned char d[],unsigned char s[],unsigned char strsz);
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// INITIALIZATION FUNCTIONS
//..............................................................................
void ini_wdt(void)
{ WDTCTL = WDTPW + WDTHOLD ; } // pswd + stop
//.............................................................................
void ini_rosc(void)
{ // internal RC oscillator
BCSCTL1 = 0xc7 ; // XTOFFF + XTS + RSEL=7(?)
DCOCTL = 0xe0 ; // DCO = 7 (max fqv) : Rext=100k (R29)
BCSCTL2 |= DCOR ; // choose external resistor
} // MCLK ~ 10Mhz (overclock)
//.............................................................................
void ini_tim(void)
{
TACTL = TASSEL_2 + MC_0 ; // SMCLK + stop timer
CCTL1 &= ~CAP ; // compare mode
CCTL1 |=OUTMOD_1 ; // set mode
}
//.............................................................................
void ini_gpio(void)
{
P1SEL = 0x00 ; // all GPIO
P1DIR = 0x0f ; // LEDs = out
P2SEL = 0x01 ; // P2.0 = out = ACLK
P2DIR = 0x01 ; // only for XTAL
P3SEL = 0x3e ; // P3.0 = SCIO = GPIO
P3OUT = 0x01 ; // P3.0 = 1
P3DIR = 0x5b ; // P3.0 = OUT
P3OUT = 0x01 ; // P3.0 = 1
}
// ¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO CONTROL FUNCTIONS
//........................................................................
void mak(void)
{ P3OUT &= ~SCIO ; // P3.0 = 0
dlthb() ; // dly halfbit through timer
// dlihb() ; // dly halfbit through instructions
P3OUT |= SCIO ; // P3.0 = 1
dlthb() ; // dly halfbit through timer
// dlihb() ; // dly halfbit through instructions
}
//........................................................................
void nomak(void)
{ P3OUT |= SCIO ; // P3.0 = 1
dlthb() ; // dly halfbit through timer
// dlihb() ; // dly halfbit through instructions
P3OUT &= ~SCIO ; // P3.0 = 0
dlthb() ; // dly halfbit through timer
// dlihb() ; // dly halfbit through instructions
}
//.........................................................................
void sak(void) // SAK = 0 - 1
{ unsigned char wait=timeout ; // init "wait" variable
// P3OUT |= SCIO ; // P3.0 = 1
P3DIR = 0x5a ; // P3.0 = INPUT
while (P3IN&SCIO) // if SCIO = 1
{ wait-- ; // decrement timeout variable
if(wait==0){ferror() ;} } // if timeout , final error
dlthb() ; dlthb() ; // wait a bit period
//dlihb() ; dlihb() ; // wait a bit period
if(!(P3IN&SCIO)) // no edge inside SAK
{ ferror() ; } // same error inside SAK
else
{ P3OUT |= SCIO ; // set P3.0
P3DIR=0x5b ; } } // if no_error, P3.0=OUTPUT
//.........................................................................
void sakq(void) // sample : 1/4 bit + 3/4 bit(QB)
{
//P3OUT |= SCIO // P3.0 = 1
P3DIR = 0x5a ; // P3.0 = INPUT
dltqb() ; // wait quarter bit
//dliqb() ; // wait quarter bit
if(P3IN&SCIO){ferror();} // pin=1 at (1/4) bit, error
else {
dlthb() ; // wait half bit till 3/4 bit
//dlihb() ; // wait half bit till 3/4 bit
if(!(P3IN&SCIO)) // if pin=0 at (3/4) bit
{ ferror() ; } // error
else {
dltqb() ; // wait till the end of bit
//dliqb() ; // wait till the end of bit
P3DIR=0x5b ; } // restore pin as OUTPUT
} }
//.........................................................................
void nosak(void)
{ unsigned char wait=timeout ; // init wait variable
// P3OUT |= SCIO ; // P3.0 = 1
P3DIR = 0x5a ; // P3.0 = INPUT
while(!(P3IN&SCIO)) // wait pin=1
{ wait-- ;
if(wait==0){ferror(); } } // timeout, same errror as in SAK
dlthb() ; dlthb() ; // wait end of bit
// dlihb() ; dlihb() ; // wait end of bit
P3DIR = 0x5b ; } // restore pin as OUTPUT
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// SERIALIZATION FUNCTIONS
//.........................................................................
void uni_wr(void) // writes an 8b streaming
{ unsigned char bitmask = 0x80 ; // bit mask for the char
while(bitmask) // for 8 bits
{ if(eep_buf&bitmask) // if ( bit=1)
{ P3OUT &= ~SCIO ; // bit=1 --> 0-1
dlthb() ; // pin=0 + hfbit delay
// dlihb() ; // pin=0 + hfbit delay
P3OUT |= SCIO ; // pin=1
dlthb() ; // pin=1 + hfbit delay
// dlihb() ; // pin=1 + hfbit delay
}
else
{ P3OUT |= SCIO ; // bit=0 --> 1-0
dlthb() ; // pin=1 + hfbit delay
// dlihb() ; // pin=1 + hfbit delay
P3OUT &= ~SCIO ; // pin=0
dlthb() ; // pin=0 + hfbit delay
// dlihb() ; // pin=0 + hfbit delay
}
bitmask = bitmask >>1 ; } } // shift right mask for 8 bits
//..........................................................................
unsigned char uni_rdq(void) // reads an 8b streaming
{ unsigned char bitmask = 0x80 ; // bit mask for the char
// P3OUT |=SCIO ; // P3.0 = 1
P3DIR = 0x5a ; // SCIO = input
while(bitmask) // for 8 bits
{
dltqb() ; // first smpl = (1/4) bit
// dliqb() ; // first smpl = (1/4) bit
if(!(P3IN&SCIO)) // if first sample=0
{
dlthb() ; // wait a half bit period
// dlihb() ; // wait a half bit period
if(!(P3IN&SCIO)) { ferror() ; } // if 2nd smpl=0, 0&&0->error
else { eep_buf|=bitmask ; } } // 0 && 1 => 1
else
{ // if first smpl=1
dlthb() ; // wait a half bit period
// dlihb() ; // wait a half bit period
if(P3IN&SCIO) { ferror() ; } // if 2nd smpl=1,1&&1->error
else { eep_buf &= ~bitmask ; } } // 1 && 0 => 0
dltqb() ;
// dliqb() ; // final quarter bit delay
bitmask = bitmask >>1 ; } // shift right mask for 8 bits
P3DIR = 0x5b ; return eep_buf ; } // pin = out , return data buffer
//..............................................................................
unsigned char uni_rd3q(void) // reads an 8b streaming
{ unsigned char bitmask = 0x80 ; // bit mask for the char
// P3OUT |=SCIO ; // P3.0 = 1
P3DIR = 0x5a ; // SCIO = input
while(bitmask) // for 8 bits
{
// dltqb() ; // delay (1/4) bit
dliqb() ; // first smpl = (1/4) bit
// dlthb() ; // wait a half bit period
dlihb() ; // wait a half bit period
if(!(P3IN&SCIO)) // sample at 3/4 bit
{ eep_buf &= ~bitmask ; } // if (3/4)bit = 0 --> bit = 0
else { eep_buf|=bitmask ; } // if (3/4)bit = 1 --> bit = 1
dliqb() ; // final quarter bit delay
bitmask = bitmask >>1 ; } // shift right mask for 8 bits
P3DIR = 0x5b ; return eep_buf ; } // pin = out , return data buffer
//..............................................................................
void uni_wrmns(void) // write + MAK + NOSAK
{ eep_buf = START ; uni_wr() ; // stream out 'START' previously loaded
mak() ; nosak() ; } // master ACK + slave NOACK
//...........................................................................
void uni_wrms(unsigned char ms) // write + MAK + SAK
{ eep_buf = ms ; uni_wr() ; // stream out 'eep_buf' previously loaded
mak() ; // master ACK
sak() ; // slave ACK
// sakq() ; // slave ACK (quarter bit)
}
//...........................................................................
void uni_wrnms(unsigned char nms) // write + NOMAK + SAK
{ eep_buf = nms ; uni_wr() ; // stream out 'eep_buf' previously loaded
nomak() ; // master NOACK
sak() ; // slave ACK
// sakq() ; // slave ACK ( quarter bit )
}
// ¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO HEADER FUNCTIONS
// ............................................................................
void uni_head(void) // first time , after POR
{
P3OUT &= ~SCIO ; // clear pin
dlythdr() ; // Thdr delay
P3OUT |= SCIO ; // set pin
dlystby() ; // Tstby delay
P3OUT &= ~SCIO ; // clear pin ( before START )
dlythdr() ; } // Thdr
//..............................................................................
void uni_head2(void) // for consecutive commands
{ P3OUT |= SCIO ; // set pin
dlytss() ; // Tss delay
P3OUT &= ~SCIO ; // clear pin ( before START )
dlythdr() ; } // Thdr
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO COMMAND FUNCTIONS
//..............................................................................
void uni_cmnd(unsigned char cmnd) // WREN , WRDI , ERAL , SETAL
{ uni_head() ; // perform the POR header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x04 ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x05 ;
uni_wrnms(cmnd) ; } // end with : wr(cmnd) + nomak + sak
//..............................................................................
void uni_cmnd2(unsigned char cmnd) // WREN , WRDI , ERAL , SETAL
{ uni_head2() ; // perform the 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x04 ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x05 ;
uni_wrnms(cmnd) ; } // end with : wr(cmnd) + nomak + sak
//...............................................................................
void uni_eral(void) // erase entire array (00)
{ uni_cmnd(WREN) ; // ERAL needs WREN
uni_cmnd(ERAL) ; // ERAL command
dly5ms() ; dly5ms() ; } // ERAL/SETAL need 10ms Twc
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//...............................................................................
void uni_eral2(void) // erase entire array(00)-consecutive cmnd
{ uni_cmnd2(WREN) ; // ERAL needs WREN
uni_cmnd2(ERAL) ; // ERAL command
dly5ms() ; dly5ms() ; } // ERAL/SETAL need 10ms Twc
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//...............................................................................
void uni_setal(void) // set entire array (ff)
{ uni_cmnd(WREN) ; // SETAL needs WREN
uni_cmnd(SETAL) ; // SETAL command
dly5ms() ; dly5ms() ; } // ERAL/SETAL need 10ms Twc
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//...............................................................................
void uni_setal2(void) // set entire array(ff)-consecutive cmnd
{ uni_cmnd2(WREN) ; // SETAL needs WREN
uni_cmnd2(SETAL) ; // SETAL command
dly5ms() ; dly5ms() ; } // ERAL/SETAL need 10ms Twc
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//...............................................................................
void uni_wrsr(unsigned char stat) // write to status register (after POR)
{ uni_head() ; // perform the first header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x01 ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x02 ;
uni_wrms(WRSR) ; // wr(WRSR) + mak + sak
err_cnt = 0x03 ;
uni_wrnms(stat) ; // end with : wr + nomak + sak
dly5ms() ; } // 5msec = Twc
// The list of error messages is presented in the 'main' function.
//..............................................................................
void ini_unio(void)
{ uni_wrsr(NOPROT) ; // write in status reg - NOPROT = 00
} // disable all write protections
//..............................................................................
unsigned char uni_rdsr(void) // read the status register
{ uni_head2() ; // (second) consecutive header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
uni_wrms(RDSR) ; // wr(RDSR) + mak + sak
uni_rdq() ; // eep_buf = status reg
// uni_rd3q() ;
nomak() ; // master NOACK
// sakq() ; // SAK with quarter bit sampling
sak() ; // SAK with normal sampling
return eep_buf ; } // return the result of uni_rdq
//..............................................................................
void uni_wippol(void) // polling of WIP flag = bit0 of SR
{ while(uni_rdsr()&0x01) ; // wait the flag to be cleared by hw
} // may replace Twc
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO BYTE ACCESS FUNCTIONS
// The list of error messages is presented in the 'main' function.
//..............................................................................
void uni_wrbyte(unsigned int eep_adr, unsigned char eep_data)
{ // writes a byte at the spec address
uni_cmnd2(WREN) ; // first, enable writes, consecutive cmnd
uni_head2() ; // 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x06 ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x07 ;
uni_wrms(WRITE) ; // wr(WRITE) + mak + sak
err_cnt = 0x08 ;
uni_wrms(eep_adr>>8) ; // wr(eep_adr>>) + mak + sak
uni_wrms(eep_adr&0xff) ; // wr(eep_adr&0xff) + mak + sak
err_cnt = 0x0a ;
uni_wrnms(eep_data) ; // wr(eep_data) + nomak + sak
dly5ms() ; // write cycle time after each byte
// uni_wippol() ; // pol WIP flag as Twc
}
//...........................................................................
void uni_rdbyte(unsigned int eep_adr, unsigned char *dst)
{ // reads a byte from the spec adr
uni_head2() ; // 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x0b ;
uni_wrms(DEVADR) ; // wr + mak + sak
err_cnt = 0x0c ;
uni_wrms(READ) ; // wr + mak + sak
err_cnt = 0x0d ;
uni_wrms(eep_adr>>8) ; // wr + mak + sak
uni_wrms(eep_adr&0xff) ; // wr + mak + sak
err_cnt = 0x0f ;
uni_rdq() ; // eep_buf = read data byte
// don't loose time storing now the result
// uni_rd3q() ;
nomak() ; // master noack
sak() ; // slave ack
// sakq() ; // slave ack ( quarter bit )
*dst = eep_buf ; // store read byte in the end
}
//...........................................................................
void uni_crrdbyte(unsigned char *dst)
{ // reads a byte from the crt adr
uni_head2() ; // 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x0b ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x0c ;
uni_wrms(CRRD) ; // wr(CRRD) + mak + sak
err_cnt = 0x0f ;
uni_rdq() ; // eep_buf = read data byte
// don't loose time storing now the result
// uni_rd3q() ;
nomak() ; // master noack
sak() ; // slave ack
// sakq() ; // slave ack (quarter bit)
*dst = eep_buf ; // store read byte in the end
}
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO STRING ACCESS FUNCTIONS
//...........................................................................
void uni_wrstr(unsigned char *source,unsigned int eep_adr,unsigned char lofsstr)
// writes a string at the spec addr ; the length of the string(source) must be :
// lofsstr = [2 - 16] ; for single byte strings use "uni_wrbyte"
{
unsigned char k = 0 ; ; // init char counter inside the string
copystr(load,source,lofsstr) ; // bring inside the function the string
uni_cmnd2(WREN) ; // enable writes
uni_head2() ; // header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x06 ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x07 ;
uni_wrms(WRITE) ; // wr(WRITE) + mak + sak
err_cnt = 0x08 ;
uni_wrms(eep_adr>>8) ; // wr(eep_adr>>8) + mak + sak
uni_wrms(eep_adr&0xff) ; // wr(eep_adr&0xff) + mak + sak
err_cnt = 0x09 ;
while(k<lofsstr-1) // for (n-1) bytes
{ uni_wrms(load[k]) ; k++ ; } // wr(bytes) + mak + sak
err_cnt = 0x0a ;
uni_wrnms(load[k]) ; // wr(last byte) + nomak + sak
dly5ms() ; // final write cycle time
// uni_wippol() ; // polling WIP flag
}
//.............................................................................
void uni_rdstr(unsigned char *dest,unsigned int eep_adr,unsigned char lofdstr)
// reads a string from the spec addr ; the length of the destination string
// must be : lofdstr = [ 2 - 16 ] ; for single byte strings use "uni_rdbyte"
{
unsigned char k = 0 ; ; // init char counter inside the string
uni_head2() ; // 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x0b ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x0c ;
uni_wrms(READ) ; // wr(READ) + mak + sak
err_cnt = 0x0d ;
uni_wrms(eep_adr>>8) ; // wr(eep_adr>>8) + mak + sak
uni_wrms(eep_adr&0xff) ; // wr + mak + sak
err_cnt = 0x0e ;
while(k<lofdstr-1) // for (n-1) bytes
{
uni_rdq() ; // eep_buf = read bytes
// uni_rd3q() ;
// don't loose time now to store data
mak() ; // master ACK
sak() ; // slave ACK
// sakq() ; // slave ACK with quarter bit
load[k] = eep_buf ; k++ ; } // store locally data, incr counter
err_cnt = 0x0f ;
uni_rdq() ; // eep_buf = last read byte
// uni_rd3q() ;
nomak() ; // master NOACK
sak() ; // slave ACK
// sakq() ; // slave ACK , quarter bit
load[k] = eep_buf ; // store locally last byte
copystr(dest,load,lofdstr) ; // internal string(load)-->dest
}
//..............................................................................
void uni_crrdstr(unsigned char *dest,unsigned char lofdstr)
// reads a string from the crt addr ; the length of the destination string
// must be : lofdstr = [ 2 - 16 ] ; for single byte strings use "uni_crrdbyte"
{
unsigned char k = 0 ; // init char counter inside the string
uni_head2() ; // 2nd header of the protocol
uni_wrmns() ; // wr(START) + mak + nosak
err_cnt = 0x0b ;
uni_wrms(DEVADR) ; // wr(DEVADR) + mak + sak
err_cnt = 0x0c ;
uni_wrms(READ) ; // wr(READ) + mak + sak
err_cnt = 0x0e ;
while(k<lofdstr-1) // for (n-1) bytes
{
uni_rdq() ; // eep_buf = read bytes
// uni_rdq() ;
// don't loose time now to store data
mak() ; // master ACK
sak() ; // slave ACK
// sakq() ; // slave ACK with quarter bit
load[k] = eep_buf ; k++ ; } // store locally data, incr counter
err_cnt = 0x0f ;
uni_rdq() ; // eep_buf = last read byte
// uni_rd3q() ;
nomak() ; // master NOACK
sak() ; // slave ACK
// sakq() ; // slave ACK , quarter bit
load[k] = eep_buf ; // store locally last byte
copystr(dest,load,lofdstr) ; // internal string(load)-->dest
}
// Not yet tested on this micro. For more details see the data sheet of the
// memory and the related app note (AN1184) - UNIO on 8051 + asm
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// UNIO AUXILIARY FUNCTIONS
//..............................................................................
void dltim(unsigned int steps)
{ // delay through timer_A <10Mhz>
// offset=4us, step=0.1us
TACTL = MC_0 + TACLR ; // stop and clear timer
CCR1 = steps ; // load delay value
TACTL = TASSEL_2 + MC_2 ; // SMCLK + continous mode
while(!(CCTL1 & CCIFG)) ; // wait CCIFG
CCTL1 &= ~CCIFG ; // clear CCIFG
TACTL = TASSEL_2 + MC_0 ; // stop timer
}
//..............................................................................
void dlins(unsigned int steps)
{ // delay through instructions
unsigned int k ; // offset=2us , step=0.5us
for(k=0;k<steps;k++)
{;} }
//...............................................................................
// CALCULATE global variables : tqb , thb , iqb , ihb . They must be calculated
// in a separate initialization function , in order to avoid loss of time
// inside delay functions. Derived from "dltim" & "dlins" functions, we will use
// dltqb(tqb) , dlthb(thb) , dliqb(iqb) , dlihb(ihb) functions.
// Moreover, we will avoid : dltim(tqb) , etc, because this call will also loose
// processing bandwidth.
// FORMULAS : ( don't forget that the timer delay has a 4us offset (40steps<0.1us>)
// and instruction based delay has a 2us offset (4steps<0.5us>) )
//................................................................................
//dltqb(tqb) = QBT = 40steps(4us) + tqb
// tqb = QBT - 40steps(4us)
//dlthb(thb) = HBT = 40steps(4us) + thb = 2*QBT
// thb = 2*QBT - 40steps(4us)
//................................................................................
//dliqb(iqb) = QBI = 04steps(2us) + iqb
// iqb = QBI - 04steps(2us)
//dlihb(ihb) = HBI = 04steps(2us) + ihb = 2*QBI
// ihb = 2*QBI - 04steps(2us)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void calcdly(void) // tqb , thb , iqb , ihb
{
tqb = QBT - 40 ; // quarter bit ( timer )
thb = 2*QBT - 40 ; // half bit ( timer )
iqb = QBI - 4 ; // quarter bit ( instr )
ihb = 2*QBI - 4 ; // half bit ( instr )
}
//.................................................................................
void dlthb(void)
{ // delay HB through timer
// offset=4us, step=0.1us
TACTL = MC_0 + TACLR ; // stop and clear timer
CCR1 = thb ; // load delay value hf bit
TACTL = TASSEL_2 + MC_2 ; // SMCLK + continous mode
while(!(CCTL1 & CCIFG)) ; // wait CCIFG
CCTL1 &= ~CCIFG ; // clear CCIFG
TACTL = TASSEL_2 + MC_0 ; // stop timer
}
//..............................................................................
void dltqb(void)
{ // delay QB through timer
// offset=4us, step=0.1us
TACTL = MC_0 + TACLR ; // stop and clear timer
CCR1 = tqb ; // load delay value hf bit
TACTL = TASSEL_2 + MC_2 ; // SMCLK + continous mode
while(!(CCTL1 & CCIFG)) ; // wait CCIFG
CCTL1 &= ~CCIFG ; // clear CCIFG
TACTL = TASSEL_2 + MC_0 ; // stop timer
}
//..............................................................................
void dlihb(void)
{ // delay HB through instructions
unsigned int k ; // offset=2us , step=0.5us
for(k=0;k<ihb;k++) {;} } //
//...............................................................................
void dliqb(void)
{ // delay QB through instructions
unsigned int k ; // offset=2us , step=0.5us
for(k=0;k<iqb;k++) {;} } //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void dlythdr(void) // short low pulse before START
{
dltim(100) ; // 100 timer steps = 10us
// dlins(20) ; // 20 instr steps = 10 us
}
//...............................................................................
void dlytss(void) // short high pulse for consecutive cmnds
// instead STBY
{ dltim(400) ; } // 400 timer steps = 40us
//...............................................................................
void dlystby(void)
{ dltim(8000) ; } // 8,000 timer steps = 800us(>600us)
//...............................................................................
void dly5ms(void)
{ dltim(50000) ; } // 50,000 timer steps = 5,000us = 5ms
//...............................................................................
void dly250ms(void)
{ unsigned char k = 50 ; // 50 * 5ms = 250 ms
while(--k) { dly5ms() ; } } // usefull for messages display
//...............................................................................
void dly1s(void)
{ dly250ms() ; dly250ms() ;
dly250ms() ; dly250ms() ; } // 4 * 250 ms = 1 sec
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
void ferror(void) // final error , for low level functions
{
while(1) // flash infinetely
{ P1OUT = ~err_cnt ; dly1s() ; // LEDs active on "0"
P1OUT = 0xff ; dly1s() ; } }
//................................................................................
void copystr(unsigned char d[],unsigned char s[],unsigned char strsz)
{ unsigned char n ;
for(n=0;n<strsz;n++)
{ d[n]=s[n] ; } } // copy source in destination
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// MAIN FUNCTION
//................................................................................
// A 4 bits counter displayed on LEDs means that everything is OK :
// no errors in the low level functions, reads = writes.
// A 2Hz blinking (00-0f) means that the code didn't detect any error in low level
// functions, but reads <> writes.
// A 0.5Hz blinking ( 00 - 01, 00 - 02 , ... , 00 - 0f ) detects an error in
// a low level function . The related error_list is presented down the page.
void main(void)
{
#define ADR0 0x0020 // initialization of the address
#define RND_MODE 0 // random byte access mode
#define PG_MODE 1 // page access mode
// ..........................................................................
unsigned char access_mode = RND_MODE ; // set the access mode to RAND
// unsigned char access_mode = PG_MODE ; // set the access mode to PAGE
unsigned int adr_cnt ; // address counter
unsigned char ch_cnt ; // character counter inside strings
unsigned char *src_str = "UNI_MSP_CCC_BB.C" ;
// source string which will be written
// UNI = UNIO protocol - MSP=MSP430 family
// CCC = "C" language , BB = bitbang meth
unsigned char dst_str[STRSZ]; // destination string,read from the eep
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// call all initialization routines
ini_wdt() ; // W.D.T.'s init
ini_rosc() ; // oscillator's init-RCosc-Rext=100k
ini_gpio() ; // GPIO's init
ini_tim() ; // Timers' init
calcdly() ; // calculates externally values of dlys
// do not loose time inside functions
//............................................................................
// below, few test functions for delays (through instructions & timer)
// keep in mind that : main clock ~ 10Mhz ( overclock )
// tqb = QBT - 40 / thb = 2*QBT - 40 (100ns resolution & 4us offset)
// iqb = QBI - 04 / ihb = 2*QBI - 04 (0.5us resolution & 2us offset)
// long delays are performed through timer_A
// short delays are performed through timer or instructions
// QBT_max = 0xa0 = 160 * 100ns ~ 16us ( bit > 64us [ < 015Khz ] )
// QBT_min = 0x28 = 040 * 100ns ~ 04us ( bit > 16us [ < 060Khz ] )
// QBI_max = 0x20 = 032 * 500ns ~ 16us ( bit > 64us [ < 015Khz ] )
// QBI_min = 0x04 = 004 * 500ns ~ 02us ( bit > 08us [ < 125Khz ] )
//............................................................................
goto ini ;
// goto s1 ; // jmp to 1sec LEDs toggle
// goto ms250 ; // jmp to 0.25sec LEDs toggle
// goto tim ; // jmp to short delays through timer
// goto ins ; // jmp to short delays through instructions
// goto ms5 ; // jmp to 5msec delay through timer
s1: while(1)
{ P1OUT = 0x00 ; dly1s() ; // toggle LEDs at a rate
P1OUT = 0x0f ; dly1s() ; } // of 1 second
ms250: while(1)
{ P1OUT = 0x00 ; dly250ms() ; // toggle LEDs at a rate
P1OUT = 0x0f ; dly250ms() ; } // of 0.25 seconds
tim: while(1)
{ P3OUT |= SCIO ; dltqb() ; // toggle P3.0 at QB timer
P3OUT &=~SCIO ; dltqb() ;
P3OUT |= SCIO ; dlthb() ; // toggle P3.0 at HB timer
P3OUT &=~SCIO ; dlthb() ; }
ins: while(1)
{ P3OUT |= SCIO ; dliqb() ; // toggle P3.0 at QB instructions
P3OUT &=~SCIO ; dliqb() ;
P3OUT |= SCIO ; dlihb() ; // toggle P3.0 at HB instructions
P3OUT &=~SCIO ; dlihb() ; }
ms5: while(1)
{ P3OUT |= SCIO ; dly5ms() ; // toggle P3.0 at 5msec
P3OUT &=~SCIO ; dly5ms(); }
//...........................................................................
ini: ini_unio() ; // INIT UNIO memory
// write(#00)-->status register
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// WRITE SOURCE STRING IN EEPROM
//............................................................................
if(access_mode==RND_MODE) // if RANDOM MODE
{ ch_cnt=0 ; adr_cnt=ADR0 ; // initialize char & address counters
while(ch_cnt<STRSZ) // repeat till the end of the string
{uni_wrbyte(adr_cnt,src_str[ch_cnt]); // write a random byte
ch_cnt++ ; adr_cnt++ ; } } // increment both counters
else // if PAGE MODE
{uni_wrstr(src_str,ADR0,STRSZ) ; } // write (page mode) from the source
// string , beginning from ADR0 address
// length of the string = STRSZ
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// READ EEPROM IN THE DESTINATION STRING
// ............................................................................
if(access_mode==RND_MODE) // in RANDOM MODE
{ch_cnt=0 ; adr_cnt=ADR0 ; // init both counters : char & address
while(ch_cnt < STRSZ) // repeat till the end of the string
{uni_rdbyte(adr_cnt,dst_str+ch_cnt); // fill the destination string with chrs
ch_cnt++ ; adr_cnt++ ; } } // increment both counters (chr&address)
else
{uni_rdstr(dst_str,ADR0,STRSZ) ; } // in PAGE MODE , sequential read
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// COMPARE SOURCE & DESTINATION STRINGS
//............................................................................
for(ch_cnt=0;ch_cnt<STRSZ;ch_cnt++)
{if((*(dst_str+ch_cnt)) != (*(src_str+ch_cnt)))
// compare the 2 strings(source & dest)
{ while(1) // in case of mismatch
{P1OUT = 0x00 ; dly250ms() ; // flash forever 00 - 0f , 4 / second
P1OUT = 0x0f ; dly250ms() ; } } // on P1 (4 LEDs)
else {P1OUT = ~ch_cnt ; // if coincidence,display counter on LEDs
dly250ms() ; // 4 bytes /second for a visual control
} } // repeat till the end of the string
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
while(1) // as final sign of sucess, display
{ for(ch_cnt=0;ch_cnt<16;ch_cnt++) // on LEDs (infinetelly) a counter
{ P1OUT = ~ch_cnt ; dly250ms() ; } } // 4 bytes / second
} // END MAIN
//¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
// LIST OF ERROR MESSAGES
//.............................................................................
// error_01 = WRSR-DEVADR error_02 = WRSR-WRSR cmnd error_03 = wr to SREG
// error_04 = WREN-DEVADR error_05 = WREN-WREN cmnd
// error_06 = WRITE-DEVADR error_07 = WRITE-WRITE cmnd error_08 = WRITE-address
// error_09 = WRITE-(n-1)DB error_10 = WRITE last data byte ( or random byte )
// error_11 = READ-DEVADR error_12 = READ-READ cmnd error_13 = READ-address
// error_14 = READ-(n-1)DB error_15 = READ last byte ( or random byte )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment