File "driver.c"
Full Path: /home/analogde/www/PIC18F452/driver.c
File size: 22.36 KB
MIME-type: text/x-c
Charset: utf-8
/**********************************************************************/
/* */
/* File name: driver.c */
/* */
/* Since: 2002/12/03 */
/* */
/* Version: 1.02 */
/* */
/* Author: MONTAGNE Xavier [XM] {link xavier.montagne@wanadoo.fr} */
/* */
/* Purpose: Offer low level functions for basic PIC programming */
/* procedures. Have a look at the Microchip specifications */
/* for further details. */
/* */
/* Distribution: This file is part of PP18. */
/* PP18 is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2, or (at your option) */
/* any later version. */
/* */
/* PP18 is distributed in the hope that it will be */
/* useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with PP18; see the file */
/* COPYING.txt. If not, write to the Free Software */
/* Foundation, 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/* History: */
/* 2002/12/03 [XM] Create this file */
/* 2003/06/26 [XM] Added the Delay_Prog management. */
/* */
/**********************************************************************/
/***********************************************************************
* INCLUDES
**********************************************************************/
#include "driver.h"
/***********************************************************************
* DEFINES.
**********************************************************************/
#define MOVLW 0x0E00
#define MOVWF 0x6E00
#define TBLPTRL_ad 0xF6
#define TBLPTRH_ad 0xF7
#define TBLPTRU_ad 0xF8
/*
* As specified in PIC18C ICSP specification.
*/
#define NB_BIT_PER_INST 4
#define NB_BIT_PER_DATA 16
#define NB_BIT_PER_HALF_DATA 8
/***********************************************************************
* MACROS
**********************************************************************/
#define WriteOpNOP() WriteOp(0x00)
#define WriteOpTRNoChange() WriteOp(0x08)
#define WriteOpTRPostInc() WriteOp(0x09)
#define WriteOpTRPostDec() WriteOp(0x0a)
#define WriteOpTRPreInc() WriteOp(0x0b)
#define WriteOpTWNoChange() WriteOp(0x0c)
#define WriteOpTWPostInc() WriteOp(0x0d)
#define WriteOpTWPostDec() WriteOp(0x0e)
#define WriteOpTWPreInc() WriteOp(0x0f)
#ifdef LINUX
#include <sys/io.h>
#define pport_in(value, port_adr) value = inb(port_adr)
#define pport_out(value, port_adr) outb(value, port_adr)
#else
#ifdef WITHOUT_PIC
#include <stdlib.h>
#include <stdio.h>
#define pport_in(value, port_adr) value = (rand())%0xFF;
#define pport_out(value, port_adr)
#else
#define pport_in(value, port_adr) __asm mov dx, port_adr ;\
__asm in al, dx ;\
__asm mov value, al
#define pport_out(value, port_adr) __asm mov dx, port_adr ;\
__asm mov al, value ;\
__asm out dx, al
#endif /* WITHOUT_PIC */
#endif /* LINUX */
/***********************************************************************
* Function prototypes.
**********************************************************************/
static void WriteRB6_RB7(unsigned char);
static void WriteRB6_RB7Delay(unsigned char val);
static void WriteOp(unsigned char TBLWT);
static void WriteOpDelay(unsigned char TBLWT);
static void WriteData(unsigned short data);
static void WriteDataAtTBLPTR(unsigned short data, ACTION action);
static void ReadDataAtTBLPTR(unsigned char *data, ACTION action);
static unsigned char ReadData(void);
static void SetTBLPTR(unsigned int location);
static void SelectBit(pr_Signal *ptr_bit, PIN_LABEL name);
/***********************************************************************
* Global variables.
**********************************************************************/
pr_ValSignal CLOCK = { PL_CLOCK, RB6_MASK, NON_INVERTED };
pr_ValSignal DATA_TO_PIC = { PL_DATA_TO_PIC, RB7_MASK, NON_INVERTED };
pr_ValSignal DATA_FROM_PIC = { PL_DATA_FROM_PIC, BUSY_MASK, INVERTED };
pr_ValSignal MCLR_VPP = { PL_VPP, MCLR_MASK, INVERTED };
pr_ValSignal VCC_ON = { PL_VCC, VCC_ON_MASK, INVERTED };
/***** Value in data parallele port register. *************************/
unsigned char data_bus;
unsigned short LPT_adr_out = PPORT_OUT_ADR;
unsigned short LPT_adr_in = PPORT_IN_ADR;
unsigned int delay_IO = 400;
unsigned int delay_Prog = 5;
/***********************************************************************
* Stuck at 0 all of the signals (logical 0, not necessarily physical 0).
*
* @param void
* @return void
**********************************************************************/
void _InitHardware(void)
{
ClearBit(PL_CLOCK);
ClearBit(PL_DATA_TO_PIC);
ClearBit(PL_VPP);
ClearBit(PL_VCC);
}
/***********************************************************************
* Set VCC_ON bit physicaly at 1.
*
* @param void
* @return void
**********************************************************************/
void _PowerOn(void)
{
unsigned int j;
/* 10 ms delay */
/* LPT port transfer rate = 150 ko/s */
for (j = 0; j < 1500; j++)
SetBit(PL_VCC);
}
/***********************************************************************
* Clear VCC_ON bit physicaly at 0.
*
* @param void
* @return void
**********************************************************************/
void _PowerOff(void)
{
ClearBit(PL_VCC);
}
/***********************************************************************
* Write a buffer into the memory of the PIC.
* A programmable delay exists to avoid any transfert problem with
* low speed communication PIC. Full speed is default speed.
*
* @param u_int adr IN Start address in the PIC address
* @param u_short *block IN Buffer start address
* @param u_int size IN Number of SHORT to write
* @param u_int *try_done IN For compatibility with JW version
* @param u_int word_programmed IN Number of SHORT programmed
* @return void
**********************************************************************/
void ProgramBlock(unsigned int adr, unsigned short *block, unsigned int size, unsigned int *try_done, unsigned int *word_programmed)
{
unsigned int i, j, word_prg;
unsigned short value;
for (j = 0; j < 1500; j++)
SetBit(PL_VPP);
/* Precharge phase */
SetTBLPTR(0x3C0006);
WriteDataAtTBLPTR(0x00, NO_CHANGE);
WriteOpNOP();
WriteData((unsigned short)(0x8EA6));
WriteOpNOP();
WriteData((unsigned short)(0x9CA6));
/* End fo Precharge phase */
word_prg = 0;
SetTBLPTR(adr);
for (i = 0; i < size; i = i + 1)
{
value = *block;
for (j = 0; (j < 3) & (size > 1); j++)
{
WriteDataAtTBLPTR(value, POST_INC);
i++;
block++;
word_prg++;
value = *block;
}
WriteDataAtTBLPTR(value, PRE_INC);
WriteOpDelay(0x00);
for (j = 0; j < delay_IO; j++)
SetBit(PL_CLOCK);
ClearBit(PL_CLOCK);
WriteData(0x0000);
WriteDataAtTBLPTR(0x0000, POST_INC);
block++;
word_prg++;
}
*try_done = i;
*word_programmed = word_prg;
ClearBit(PL_VPP);
}
/***********************************************************************
* Write a buffer into the configuration field of the PIC.
* A programmable delay exists to avoid any transfert problem with
* low speed communication PIC. Full speed is default speed.
*
* @param u_int adr IN Start address in the PIC address
* @param u_short *block IN Buffer start address
* @param u_int size IN Number of SHORT to write
* @param u_int *try_done IN For compatibility with JW version
* @param u_int word_programmed IN Number of SHORT programmed
* @return void
**********************************************************************/
void ProgramBlockCfg(unsigned int adr, unsigned short *block, unsigned int size, unsigned int *try_done, unsigned int *word_programmed)
{
unsigned int i, j, word_prg;
unsigned short value;
for (j = 0; j < 1500; j++)
SetBit(PL_VPP);
/* Precharge phase */
SetTBLPTR(0x3C0006);
WriteDataAtTBLPTR(0x00, NO_CHANGE);
WriteOpNOP();
WriteData((unsigned short)(0x8EA6));
WriteOpNOP();
WriteData((unsigned short)(0x8CA6));
/* End of precharge phase */
word_prg = 0;
SetTBLPTR(adr);
for (i = 0; i < size; i = i + 1)
{
value = *block;
for (j = 0; (j < 3) & (size > 1); j++)
{
WriteDataAtTBLPTR(value, POST_INC);
i++;
block++;
word_prg++;
value = *block;
}
WriteDataAtTBLPTR(value, PRE_INC);
WriteOpDelay(0x00);
for (j = 0; j < delay_IO; j++)
SetBit(PL_CLOCK);
ClearBit(PL_CLOCK);
WriteData(0x0000);
WriteDataAtTBLPTR(0x0000, POST_INC);
block++;
word_prg++;
}
*try_done = i;
*word_programmed = word_prg;
ClearBit(PL_VPP);
}
/***********************************************************************
* Read the memory of the PIC and store the result into a buffer.
* A programmable delay exists to avoid any transfert problem with
* low speed communication PIC. Full speed is default speed.
*
* @param u_int adr IN Start address in the PIC address
* @param u_short *block IN Buffer address
* @param u_int size IN Number of SHORT to write
* @return void
**********************************************************************/
void ReadBlock(unsigned int adr, unsigned short *block, unsigned int size)
{
unsigned int i, j;
unsigned char result_H, result_L;
unsigned short result;
for (j = 0; j < 1500; j++)
SetBit(PL_VPP);
SetTBLPTR(adr);
for (i = 0; i < size; i = i + 1)
{
ReadDataAtTBLPTR(&result_L, POST_INC);
ReadDataAtTBLPTR(&result_H, POST_INC);
result = (unsigned short)(result_L + (unsigned short)(result_H << 8));
*block = result;
block++;
for (j = 0; j < delay_IO; j++)
ClearBit(PL_CLOCK);
}
ClearBit(PL_VPP);
}
/***********************************************************************
* Erase the entier memory of the PIC.
* A programmable delay exists to avoid any transfert problem with
* low speed communication PIC. Full speed is default speed.
*
* @param void
* @return void
**********************************************************************/
void BulkErase(void)
{
unsigned int j;
for (j = 0; j < 1500; j++)
SetBit(PL_VPP);
SetTBLPTR(0x3C0004);
WriteDataAtTBLPTR(0x83, NO_CHANGE);
WriteOpNOP();
WriteData(0x0000);
WriteOpNOP();
for (j = 0; j < 5000; j++)
ClearBit(PL_CLOCK);
WriteData(0x0000);
ClearBit(PL_VPP);
SetBit(PL_VPP);
SetTBLPTR(0x3C0004);
WriteDataAtTBLPTR(0x80, NO_CHANGE);
WriteOpNOP();
WriteData(0x0000);
WriteOpNOP();
for (j = 0; j < 5000; j++)
ClearBit(PL_CLOCK);
WriteData(0x0000);
ClearBit(PL_VPP);
return;
}
/***********************************************************************
* Update the TBLPTR. It's necessary to do so before programming the
* PIC. This is the START address of the read/write sequences.
*
* @param u_int location IN Value of the TBLPTR register
* @return void
**********************************************************************/
static void SetTBLPTR(unsigned int location)
{
unsigned char TBLPTRL, TBLPTRH, TBLPTRU;
TBLPTRL = (unsigned char)(location & 0xff);
TBLPTRH = (unsigned char)((location >> 8) & 0xff);
TBLPTRU = (unsigned char)((location >> 16) & 0xff);
/* TBLPTRL */
WriteOpNOP();
WriteData((unsigned short)(MOVLW + TBLPTRL));
WriteOpNOP();
WriteData((unsigned short)(MOVWF + TBLPTRL_ad));
/* TBLPTRH */
WriteOpNOP();
WriteData((unsigned short)(MOVLW + TBLPTRH));
WriteOpNOP();
WriteData((unsigned short)(MOVWF + TBLPTRH_ad));
/* TBLPTRU */
WriteOpNOP();
WriteData((unsigned short)(MOVLW + TBLPTRU));
WriteOpNOP();
WriteData((unsigned short)(MOVWF + TBLPTRU_ad));
}
/***********************************************************************
* Write any 16 bits word into the PIC memory at the address pointed by
* TBLPTR.
*
* @param u_short data IN Data to write at TBLPTR
* @param ACTION action IN Post-inc, pre-inc,...
* @return void
**********************************************************************/
static void WriteDataAtTBLPTR(unsigned short data, ACTION action)
{
switch (action)
{
case NO_CHANGE :
WriteOpTWNoChange();
break;
case POST_INC :
WriteOpTWPostInc();
break;
case POST_DEC :
WriteOpTWPostDec();
break;
case PRE_INC :
WriteOpTWPreInc();
break;
default :
break;
};
WriteData(data);
}
/***********************************************************************
* Read any 16 bits word into the PIC memory at the address pointed by
* TBLPTR.
*
* @param u_short *data IN Data to read at TBLPTR
* @param ACTION action IN Post-inc, pre-inc,...
* @return void
**********************************************************************/
static void ReadDataAtTBLPTR(unsigned char *data, ACTION action)
{
switch (action)
{
case NO_CHANGE :
WriteOpTRNoChange();
break;
case POST_INC :
WriteOpTRPostInc();
break;
case POST_DEC :
WriteOpTRPostDec();
break;
case PRE_INC :
WriteOpTRPreInc();
break;
default :
break;
};
*data = ReadData();
}
/***********************************************************************
* Send any 8 bits command word to the PIC. The bits are sent one by
* one to the PIC via the RB6 & RB7 pins.
*
* @param u_char CMD IN Command to send to the PIC
* @return void
**********************************************************************/
static void WriteOp(unsigned char CMD)
{
unsigned char i;
for (i = 0; i < NB_BIT_PER_INST; i++)
WriteRB6_RB7((unsigned char)((CMD >> i) & 1));
}
/***********************************************************************
* Send any 8 bits command word to the PIC. The bits are sent one by
* one to the PIC via the RB6 & RB7 pins.
* Delay for special operation is added as specified in the Microchip
* specification.
*
* @param u_char CMD IN Command to send to the PIC
* @return void
**********************************************************************/
static void WriteOpDelay(unsigned char CMD)
{
unsigned char i;
for (i = 0; i < NB_BIT_PER_INST-1; i++)
WriteRB6_RB7((unsigned char)((CMD >> i) & 1));
WriteRB6_RB7Delay((unsigned char)((CMD >> NB_BIT_PER_INST) & 1));
}
/***********************************************************************
* Send any 16 bits data word to the PIC. The bits are sent one by
* one to the PIC via the RB6 & RB7 pins.
*
* @param u_short data IN Data to send to the PIC
* @return void
**********************************************************************/
static void WriteData(unsigned short data)
{
unsigned char i;
for (i = 0; i < NB_BIT_PER_DATA; i++)
WriteRB6_RB7((unsigned char)((data >> i) & 1));
}
/***********************************************************************
* Read a 16 bits data word from the PIC. The bits are read one by
* one to the PIC via the RB6 & RB7 pins.
*
* @param void
* @return u_short Data read from the PIC
**********************************************************************/
static unsigned char ReadData(void)
{
unsigned char i, data, val;
data = 0;
for (i = 0; i < NB_BIT_PER_HALF_DATA; i++)
WriteRB6_RB7((unsigned char)((data >> i) & 1));
SetBit(PL_DATA_TO_PIC);
for (i = 0; i < NB_BIT_PER_HALF_DATA; i++)
{
val = ReadBit(PL_DATA_FROM_PIC);
data |= (unsigned char)(((val) ? 1: 0) << i);
}
ClearBit(PL_DATA_TO_PIC);
return (data);
}
/***********************************************************************
* Read one bit from the PIC. The bit is one of the 5 signals of the
* programmer.
*
* @param PIN_LABEL name IN Signal name
* @return u_char LPT data value masked by the signal
**********************************************************************/
unsigned char ReadBit(PIN_LABEL name)
{
unsigned char data;
unsigned int j;
pr_Signal the_bit;
SelectBit(&the_bit, name);
for (j = 0; j < delay_Prog; j++)
SetBit(PL_CLOCK);
for (j = 0; j < delay_Prog; j++)
ClearBit(PL_CLOCK);
pport_in(data, LPT_adr_in);
if (the_bit->status & INVERTED)
data = (unsigned char)((~data) & the_bit->mask);
else
data = (unsigned char)(data & the_bit->mask);
return (data);
}
/***********************************************************************
* Write one bit on one signal from the 5 signals of the programmer.
*
* @param u_char val IN Boolean value to set on the signal
* @return void
**********************************************************************/
static void WriteRB6_RB7(unsigned char val)
{
unsigned int j;
for (j = 0; j < delay_Prog; j++)
SetBit(PL_CLOCK);
for (j = 0; j < delay_Prog; j++)
(val & 1) ? SetBit(PL_DATA_TO_PIC) : ClearBit(PL_DATA_TO_PIC);
for (j = 0; j < delay_Prog; j++)
ClearBit(PL_CLOCK);
for (j = 0; j < delay_Prog; j++)
ClearBit(PL_DATA_TO_PIC);
}
/***********************************************************************
* Write one bit on one signal from the 5 signals of the programmer.
* Special delay is added as specified by the Microchip specification.
*
* @param u_char val IN Boolean value to set on the signal
* @return void
**********************************************************************/
static void WriteRB6_RB7Delay(unsigned char val)
{
SetBit(PL_CLOCK);
(val & 1) ? SetBit(PL_DATA_TO_PIC) : ClearBit(PL_DATA_TO_PIC);
}
/***********************************************************************
* Stuck the signal at 1 (logical 1, not physical 1).
*
* @param PIN_LABEL name IN Signal name
* @return void
**********************************************************************/
void SetBit(PIN_LABEL name)
{
pr_Signal the_bit;
SelectBit(&the_bit, name);
if (the_bit->status & INVERTED)
data_bus &= (unsigned char)~the_bit->mask;
else
data_bus |= the_bit->mask;
pport_out(data_bus, PPORT_OUT_ADR);
}
/***********************************************************************
* Stuck the signal at 0 (logical 0, not physical 0).
*
* @param PIN_LABEL name IN Signal name
* @return void
**********************************************************************/
void ClearBit(PIN_LABEL name)
{
pr_Signal the_bit;
SelectBit(&the_bit, name);
if (the_bit->status & INVERTED)
data_bus |= the_bit->mask;
else
data_bus &= (unsigned char)~the_bit->mask;
pport_out(data_bus, PPORT_OUT_ADR);
}
/***********************************************************************
* Setup a signal.
*
* @param PIN_LABEL name IN Signal name
* @param u_char mask IN Mask value of the signal
* @param u_char status IN INVERTED or NOT_INVERTED
* @return void
**********************************************************************/
void ConfigBit(PIN_LABEL name, unsigned char mask, unsigned char status)
{
pr_Signal the_bit;
SelectBit(&the_bit, name);
if (mask)
the_bit->mask = mask;
the_bit->status = status;
}
/***********************************************************************
* Select a signal.
*
* @param pr_Signal *ptr_bit IN Signal pointer
* @param PIN_LABEL name IN Signal name
* @return void
**********************************************************************/
static void SelectBit(pr_Signal *ptr_bit, PIN_LABEL name)
{
switch (name)
{
case PL_DATA_TO_PIC:
*ptr_bit = &DATA_TO_PIC;
break;
case PL_DATA_FROM_PIC:
*ptr_bit = &DATA_FROM_PIC;
break;
case PL_CLOCK:
*ptr_bit = &CLOCK;
break;
case PL_VPP:
*ptr_bit = &MCLR_VPP;
break;
case PL_VCC:
*ptr_bit = &VCC_ON;
break;
}
}
/***********************************************************************
* Get the mask value of a signal.
*
* @param PIN_LABEL name IN Signal name
* @return void
**********************************************************************/
unsigned char GetMask(PIN_LABEL name)
{
pr_Signal the_bit;
SelectBit(&the_bit, name);
return (the_bit->mask);
}
/***********************************************************************
* Get the Status value of a signal.
*
* @param PIN_LABEL name IN Signal name
* @return void
**********************************************************************/
unsigned char GetStatus(PIN_LABEL name)
{
pr_Signal the_bit;
SelectBit(&the_bit, name);
return (the_bit->status);
}
/* End of file */