📄 an_gen_6x8_1_c_listing.c
字号:
//********************************
// PROJECT: CMX618 Encode/Decode Data Exchange with Serial Flash
//
// FILE: MAIN.C
//
// PROCESSOR: AT89C2051
//
// LAST MODIFIED: July 10, 2008
//
// COMMENTS:
// The purpose of this project is to:
// - receive encoded data (with FEC) from the CMX618 (on EV6180)
// - write 243 bytes of encoded data to a serial flash device (Winbond W25X80)
// - read out the data from the serial flash.
// - pass the data to the CMX618 decoder for playback
//
// C-BUS and SPI communications are "bit banged" from processor.
//********************************
#include <REG2051.H> // header file for AT89C2051
//CMX618 Register Mapping
#define RESET 0x01
#define SYNC 0x02
#define SYNCCTRL 0x04
#define AIG 0x05
#define AOG 0x06
#define VCFG 0x07
#define MVCFG 0x2C
#define SDTMF 0x08
#define POWERSAVE 0x09
#define DTMFATTEN 0x0A
#define EXCODECCONT 0x0B
#define IDD 0x0C
#define SVCREQ 0x0E
#define FRAMETYPEW 0x0F
#define DECFRAME 0x10
#define ECFIFO 0x24
#define SVCACK 0x2E
#define FRAMETYPER 0x2F
#define ENCFRAME 0x30
#define VCTRL 0x11
#define MVCTRL 0x3C
#define EXCODECCMD 0x12
#define CLOCK 0x1D
#define VDWHLWM 0x1E
#define IRQENAB 0x1F
#define DFRAMEDATA 0x37
#define EFRAMEDATA 0x38
#define STATUS 0x40
//CMX618 VCFG Register Definitions
#define HDD 0x20 //selects "hard bits" for decoding
#define FEC 0x10 //enables FEC
#define _80MSEC 0x00
#define _60MSEC 0x03
#define _40MSEC 0x02
#define _20MSEC 0x01
#define _2750BPS 0x08
#define _2400BPS 0x04
#define _2050BPS 0x00
//CMX618 VCTRL Register Definitions
#define DVDW 0x0010 //enables "Vocoder Data Wanted" function
#define ENC 0x0002 //enables CMX618 encoder
#define DEC 0x0001 //enables CMX618 decoder
#define SLEEP 0x0000 //stop encoder & decoder
//CMX618 POWERSAVE Register Definitions
#define CODEC 0x02
#define BIAS 0x01
//CMX618 IRQENAB Register Definitions
#define RDY 0x8000 //Ready (for new commands)
#define VDW 0x0100 //Vocoder Data Wanted (decode mode)
#define VDA 0x0001 //Vocoder Data Available (encode mode)
//Flash Definitions
#define WRITE_ENABLE 0x06
#define CHIP_ERASE 0xC7
#define PAGE_PROGRAM 0x02
#define READ_DATA 0x03
#define READ_STATUS 0x05
#define BUSY 0x01
#define APPEND_ONE 0x01
#define APPEND_ZERO 0xFE
#define BYTELENGTH 27 //length of CMX618 encode packet, in bytes
//adjustment of BYTELENGTH will result in...
//...adjustment of writes to flash and addressing scheme
#define ON 0
#define OFF 1
//Function Declarations
void initialize_618(void);
void initialize_uC(void);
void spi_write(unsigned char xbyte);
unsigned char spi_read(void);
void erase_flash(void);
void program_flash(unsigned char add1, unsigned char add2, unsigned char add3);
void read_flash(unsigned char m, unsigned char n, unsigned char p);
void encode_process(void);
void decode_process(void);
//C-BUS Function Declarations
void wr_byte(unsigned char byte);
void wr1(unsigned char address, unsigned char databyte);
void wr2(unsigned char address, unsigned int dataword);
unsigned char rd_byte(void);
unsigned char rd1(unsigned char address);
unsigned int rd2(unsigned char address);
//User Interface Pin Mapping
sbit ENCSWITCH = P3^7;
sbit DECSWITCH = P1^0;
sbit LED1 = P1^4;
sbit LED2 = P1^3;
sbit LED3 = P1^2;
sbit RED_LED = P1^1;
//C-BUS to uC Pin Mapping
sbit CSN = P3^5;
sbit CDATA = P3^4;
sbit RDATA = P3^3;
sbit IRQ = P3^2; //externally triggered IRQ pin
sbit SCLK = P3^1; //supplies CLK to CMX618 (C-BUS) and flash
//Flash to uC Pin Mapping
sbit SS = P1^7;
sbit DO = P1^6;
sbit DI = P1^5;
//The CLK line for flash is fed by the SCLK used by C-BUS
//Global Variables
unsigned int timer1_counter=0; //counter allows for a wide variety of delays
unsigned char CMX618_data[BYTELENGTH]; //array for CMX618 encoded & decoded data
unsigned char ENCODE_ADDRESS_HIGH=0x00; //counters for flash "page program" address increment
unsigned char ENCODE_ADDRESS_MID=0x00;
unsigned char ENCODE_ADDRESS_LOW=0x00;
unsigned char DECODE_ADDRESS_HIGH=0x00; //counters for flash "read data" address increment
unsigned char DECODE_ADDRESS_MID=0x00;
unsigned char DECODE_ADDRESS_LOW=0x00;
unsigned char spi_data=0; //data received from the SPI port ("slave in")
unsigned char state=0; //state variable: 0=config, 1=encode, 2=decode, 3=powersave
//Global Flags
bit timer1_expired=0; //flag for 20s & 100ms delay
bit busy=1; //flag for flash task completion
bit rdy=0; //CMX618 RDY bit in Status Register
bit decode_complete=0; //flag for decode completion
bit CMX618IRQ=0;
//********************************
//FUNCTION:
void initialize_618(void)
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION: CMX618 configured as follows:
// - 2400bps encode + 1200bps FEC = 3600bps = 216bits (27 bytes) in a 60ms frame
// - CMX618 on EV6180 uses 12MHz xtal.
// - IRQENAB is not written here but is instead written within "main" during encode and decode sections.
// - IDD delay register is not adjusted, so 8ms default delay is used.
// - SYNCCTRL register is not written because VDA(encode) and VDW(decode) IRQs control data pacing.
//********************************
{
//Only IRQ that is enabled on powerup is RDY
//IRQ will exist here due to hard reset
rd2(STATUS); //clear IRQ from hard reset
rdy=0; //reset RDY flag
//Perform software reset
CSN=0;
wr_byte(RESET);
CSN=1;
//Wait for RDY bit before subsequent commands
while(!rdy); //wait for RDY bit
rdy=0; //clear flags
//Basic CMX618 adjustments
wr2(CLOCK, 0x0005);
wr1(POWERSAVE, (CODEC | BIAS));
wr1(VCFG, (HDD | FEC | _2400BPS | _60MSEC));
while(!rdy); //Wait for configuration to complete...
rdy=0;
//NOTE: A check of SVCACK ($2E) b0 can be made at this point for debug purposes.
//SVCACK b0 only has meaning after a service has been performed and RDY has been asserted.
//If SVCACK b0 is not equal to 1 after RDY is asserted, an error has been made.
//In this case, a General Reset should be issued and device configuration restarted.
//Wait 100ms for Vbias to stabilize...
timer1_counter=5; //20ms x 5 = 100ms delay
timer1_expired=0; //clear flag
TR1=1; //turn on Timer 1
while(!timer1_expired);
timer1_expired=0;
//Input and output gains...
wr1(AIG, 0x8F); //Mic amp=20dB, I/P gain=22.5dB
wr1(AOG, 0x07); //Earpiece gain=0dB, O/P gain=0dB
//High and low watermarks for VDW bit
wr2(VDWHLWM, 0x809E); //High watermark=0x9E=158 samples as per datasheet example
while(!rdy);
rdy=0;
wr2(VDWHLWM, 0x0048); //Low watermark=0x48=72 samples as per datasheet example
while(!rdy);
rdy=0;
}
//********************************
//FUNCTION:
void initialize_uC(void)
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION:
// INT0 used for CMX618 IRQ detection (falling edge triggered).
// Timer 1 used for:
// - switch debouncing
// - 20sec Chip Erase lockup prevention
// - 100ms CMX618 delay for Vbias to stabilize during configuration.
//********************************
{
IE=0x89; // Enabled IRQs; Global, Timer 1, EX0.
IT0=1; // INT0 (for CMX618 C-BUS IRQ) falling-edge triggered
//Timer configuration
TMOD=0x10; // Timer 1 in 16-bit timer (Mode 1)
TH1=0xB8; // Timer 1 = 18432 counts = 20ms
TL1=0x00;
//Configure pins as inputs
P1=P1 | 0x0F; //write 1s to lower nibble for LEDs
P3_7=1; //switch configured as input
IRQ=1;
DO=1;
}
//********************************
//FUNCTION:
void CMX618_IRQ() interrupt 0
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION: Ext INT0 Interrupt Servide Routine.
// The Status register is read, and the "state" variable determines which bits will be checked.
//********************************
{
unsigned int temp=0x0000;
temp=rd2(STATUS);
switch(state)
{
case 0: //configuration mode, check for RDY bit
if((temp & 0x8000) == 0x8000)
rdy=1;
break;
case 1: //encode mode, check for VDA bit
if((temp & 0x0001) == 0x0001)
CMX618IRQ=1;
break;
case 2: //decode mode, check for VDW bit
if((temp & 0x0100) == 0x0100)
CMX618IRQ=1;
break;
case 3: //powersave mode, not actually used in this routine
break;
}
}
//********************************
//FUNCTION:
void timer1() interrupt 3
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION: Timer 1 Interrupt Servide Routine.
// This timer is used for:
// - switch debouncing within "main"
// - the 20s delay for Chip Erase lockup prevention
// - the 100ms delay needed in the CMX618 initialization.
// A counter is decremented each time Timer 1 overflows.
// When the count reaches 0, a flag is set.
//********************************
{
timer1_counter--;
if(timer1_counter==0)
{
timer1_expired=1;
TR1=0;
}
else
TR1=1;
TH1=0xB8; //reload for 20ms overflow
TL1=0x00;
}
//******************************************
// FUNCTION:
void spi_write(unsigned char xbyte)
//
// PURPOSE: Write a single byte to flash input port.
//
// DESCRIPTION: This function takes in a single-byte corresponding to the
// value to be written to the flash input port.
//
// A 'for' loop is started and the SCLK line is pulled low. The msb of the byte is obtained and
// written to flash. The byte is left-shifted one place and SCLK is pulled high to latch the bit
// into the flash. The 'for' loop iterates 7 more times to complete the byte write operation.
//
// Data into the flash DI pin is sampled on the rising edge of SCLK.
//
// This function does not return a variable.
//*******************************************
{
unsigned char i;
for(i=8; i!=0; i--)
{
SCLK=0;
if(xbyte & 0x80)
DI=1;
else
DI=0;
xbyte <<= 1;
SCLK=1;
}
}
//******************************************
// FUNCTION:
unsigned char spi_read(void)
//
// PURPOSE: Read a single byte from the flash SPI output port.
//
// DESCRIPTION: This function does not take in a variable.
//
// The SCLK line is pulled low and a 'for' loop is started. The SCLK line is pulled high to
// latch out the latest data bit, and this bit is appended to any previously received bits.
// The received bits are left-shifted one place and SCLK is pulled low.
// The 'for' loop iterates 7 more times to complete the read operation.
//
// This function returns the received byte to the calling routine.
//*******************************************
{
unsigned char ybyte=0x00, i;
SCLK=0;
for(i=0; i<8; ++i)
{
ybyte <<= 1; //left-shift here due to decrementing operator
SCLK=1;
if(DO) //append 1 to ybyte if DO=1
ybyte |= APPEND_ONE;
else //else, append 0 to ybyte
ybyte &= APPEND_ZERO;
SCLK=0;
//fast processors may need a delay here
}
return(ybyte);
}
//********************************
//FUNCTION:
void encode_process(void)
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION:
// This routine is called by the CMX618 Interrupt Service Routine if the Status register VDA bit=1.
// This routine reads out an encoded voice data packet from the CMX618 and
// writes it to flash.
//********************************
{
unsigned char i;
//Read out an encoded data packet from the CMX618
CSN=0; //start streaming C-BUS transaction
wr_byte(ENCFRAME); //write address for ENCFRAME register
for(i=0; i<BYTELENGTH; ++i)
CMX618_data[i]=rd_byte(); //read out encoded data
CSN=1; //end streaming C-BUS transaction
//Write encoded data to flash
program_flash(ENCODE_ADDRESS_HIGH, ENCODE_ADDRESS_MID, ENCODE_ADDRESS_LOW);
//Increment page address for next flash write
if(ENCODE_ADDRESS_HIGH==0xFF) //if max address = 0xFF, error condition...turn on Red LED
RED_LED=ON;
if(ENCODE_ADDRESS_LOW!=0xD8)
ENCODE_ADDRESS_LOW = ENCODE_ADDRESS_LOW + BYTELENGTH;
else //c is excessive and must be reset, but what about a and b?
{
if(ENCODE_ADDRESS_MID<0xFF) //if b is not excessive (<255), increment b and reset c
{
ENCODE_ADDRESS_LOW=0;
ENCODE_ADDRESS_MID++;
}
else //if b is excessive, increment a and reset b & c.
{
ENCODE_ADDRESS_LOW=0;
ENCODE_ADDRESS_MID=0;
ENCODE_ADDRESS_HIGH++;
}
}
}
//********************************
//FUNCTION:
void decode_process(void)
//
//INPUTS: none
//
//OUTPUTS: none
//
//DESCRIPTION: This routine transfers an encoded voice data packet to the CMX618 decoder.
// This routine is called by the CMX618 Interrupt Service Routine if the Status register VDW bit=1.
// Data is written to the CMX618 decoder first and another data packet is then read out of flash.
// This was done to ensure that data would be supplied to the decoder almost immediately after the VDW interrupt.
// (The "main" routine performs an extra "read flash" operation so that an encoded packet is
// already in memory when "decode process" is called for the first time. This should ensure that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -