2010年2月3日星期三

ARM Note

****************************
*** CRC
****************************
下面以最常用的CRC-16为例来说明其生成过程。

CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码进行异或,否则如果LSB为零,则无需进行异或。重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。

CRC的计算过程:
1.设置CRC寄存器,并给其赋值FFFF(hex)。
2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC寄存器。
3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。
4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与多项式码相异或。
5.重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。
6.重复第2至第5步直到所有数据全部处理完成。
7.最终CRC寄存器的内容即为CRC值。

The sample code searched from web:

//-- reverse order of 0x8005 (X16+X15+X2+1, CRC-16, ignored MSB X16)
//-- since we are XORing bit0 of the data
volatile unsigned short CRCPOLY16 = 0xA001;

//-- bit-at-a-time CRC-16 algorithm
unsigned short crc16( unsigned char *data, unsigned char len)
{
unsigned char i;
unsigned char j;
unsigned short byte;
unsigned short crc;
unsigned short mask;

i = 0;
crc = 0xFFFF;

while( i < len )
{
if( data[i] != 0 )
{
byte = data[i]; //-- get next byte
crc = crc ^ byte;
for( j=8; j>0; j-- )
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (CRCPOLY16 & mask);
}
}
i++;
}
return ~crc;
}

********************** END CRC *****************

**************************************************
** I2C Slave mode
**************************************************
Sample code for ARM7 :

"i2c_slave.h" :
#ifndef __I2C_SLAVE_H__
#define __I2C_SLAVE_H__

void IRQ_I2C0_SLV (void) __attribute__ ((interrupt("IRQ")));
volatile unsigned char I2C_SlaveRcv;
volatile unsigned char *I2C_SlaveSndBuf;
volatile unsigned char I2C_Snd_num;
volatile unsigned char I2C_SlvSnd_end;
volatile unsigned char I2C_NoOfByte;
void Initialize_I2C0_SLV( unsigned int irq_slot, unsigned char id, unsigned char noofbyte);
void IRQ_I2C0_SLV(void);
void I2C_Slv_SendData( unsigned char *s);

#endif // __I2C_SLAVE_H__

"i2c_slave.c" :
void Initialize_I2C0_SLV( unsigned int irq_slot, unsigned char id, unsigned char noofbyte)
{
volatile unsigned long *addr;
PINSEL0 |= 0x00000050; //-- p0.2=SDA0, p0.3=SCL0
I2C0ADR = ( id << 1); //-- set I2C slave address, shitf 1-bit left to filter r/w bit
I2C0CONSET = 0x44; //-- enable I2C hardware and set AA (ack) to enable slave mode
addr = &VICVectCntl0;
*(addr + irq_slot) = 0x00000020 | VIC_I2C0;
addr = &VICVectAddr0;
*(addr + irq_slot) = ( unsigned int ) &IRQ_I2C0_SLV;

VICIntSelect &= ~( 1 << VIC_I2C0);
VICIntEnable |= ( 1 << VIC_I2C0);

I2C_NoOfByte = noofbyte;
I2C_SlaveSndBuf = NULL;
I2C_Snd_num = I2C_NoOfByte;
I2C_SlvSnd_end = 1;
}

void IRQ_I2C0_SLV(void)
{
unsigned char sta;

sta = I2C0STAT;
//I2C0CONCLR = 0x2C; //-- clear STA, AA and SI
I2C0CONCLR = 0x24; //-- clear STA and AA

switch( sta)
{
//-- slave receiver mode
case 0x60: //-- own SLA+W has been received, ack has been returned, no I2CDAT action
I2C0CONSET = 0x04; //-- set AA, will receive data and return ACK
break;
case 0x68: //-- address as slave
I2C0CONSET = 0x04; //-- set AA, return ACK on first byte
break;
case 0x70:
break;
case 0x78:
break;
case 0x80: //-- Data received, ACK returned
I2C_SlaveRcv = I2C0DAT; //-- read and store data, NACK on next byte
I2C0CONSET = 0x04;
break;
case 0x88: //-- data received, NACK returned, will exit slave mode
I2C0CONSET = 0x04; //-- set to not addressed slave
break;
case 0xA0: //-- STOP or repeat START received with addressed as slave, will leave slave mode
I2C0CONSET = 0x04; //-- set AA to re-enter slave mode
break;

//-- slave transmitter mode
case 0xA8: //-- own SLA+R received, ACK returned (slave transmitted)
I2C_SlvSnd_end = 0; //-- start send bytes
I2C_Snd_num = I2C_NoOfByte; //-- initiate pointer
I2C0DAT = *I2C_SlaveSndBuf; //-- first byte will be sent;
I2C0CONSET = 0x04; //-- current data byte will be transmitted, ACK will be received, AA=1
break;
case 0xB0: //-- Arbitration lost, enter slave transmitter mode
break;
case 0xB8: //-- Data transmitted, ACK received
I2C_Snd_num--; //-- decrease data byte counter
I2C0DAT = *(I2C_SlaveSndBuf + (I2C_NoOfByte - I2C_Snd_num));
if( I2C_Snd_num > 0 ) //-- if not the last byte
{
I2C0CONSET = 0x04; //-- Data byte will be transmitted, ACK will be received, AA=1
}
else //-- the last byte
{
I2C0CONCLR = 0x04; //-- Last data byte will be sent and ACK will be received, AA=0
}
break;
case 0xC0: //-- Data byte transmitted, NACK received(end of master receive mode), not addressed slave entered
I2C0CONSET = 0x04; //-- set AA, switch to not addressed mode
I2C_Snd_num = I2C_NoOfByte; //-- reset counter
I2C_SlvSnd_end = 1; //-- reset end of send byte flag
break;
case 0xC8: //-- Last data transmitted, ACK received
I2C_Snd_num = I2C_NoOfByte; //-- reset counter
I2C_SlvSnd_end = 1; //-- reset end of byte flag
I2C0CONSET = 0x04; //-- Set AA, switch to not addressed slave mode
break;
default:
I2C_Snd_num = I2C_NoOfByte; //-- reset counter
I2C_SlvSnd_end = 0; //-- reset end of byte flag
break;
}
I2C0CONCLR = 0x08; //-- clear SI
VICVectAddr = 0x00; //-- reset VIC
}

void I2C_Slv_SendData( unsigned char *s)
{
if( I2C_SlvSnd_end == 1)
I2C_SlaveSndBuf = s;
}

******************** END I2C Slave mode ************************

没有评论: