Всем привет,
есть проблемы с RC522, чип инициализируется, регистры читаются и пишутся отлично но PICC_IsNewCardPresent возвращает таймаут
(в цикле PCD_CommunicateWithPICC
if (n & 0x01)
{ // Timer interrupt - nothing received in 25ms
putchr('1');
return STATUS_TIMEOUT;
}
)
код взял с
https://github.com/miguelbalboa/rfid/blob/master/MFRC522.cpp. Вообще без доработок перенес на С.
К кого есть плата RC522, плиз, проверьте, такое ощущение что что-то криво напаяли китайцы, хотя что найти не могу.
#include "global.h"
#include "rfid.h"
#include "uart.h"
#include "hardware.h"
void inline CS_HIGH(void) {PORTB |= (1<<PB4);}
void inline CS_LOW(void) {PORTB &= ~(1<<PB4);}
void inline RST_HIGH(void) {PORTC |= (1<<PC1);}
void inline RST_LOW(void) {PORTC &= ~(1<<PC1);}
#define delay _delay_ms
inline unsigned char SPI_transfer(unsigned char data)
{
unsigned char ret;
SPDR = data;
while (!(SPSR & (1<<SPIF))) ;
ret = SPDR;
return ret;
}
// SPI init
void rfid_spi_init()
{
// Port B initialization
// PB7=SCK PB6=MISO PB5=MOSI PB4=SS PB3=OUT1 PB2=OUT12 PB1=OUT10 PB0=OUT6
// Out Tri Out Out Out Out Out Out
PORTB = 0b00000000;
DDRB = 0b10111111;
// Set SS = 1, ìàñòåð äåðæèò SS = 0 âñåãäà êîãäà âêëþ÷åí
CS_HIGH();
// Reset interrupt flag
// Reset Write collision flag
// Double rate enabled
SPSR = (0<<SPIF) | (0<<WCOL) | (1<<SPI2X);
// Interrupts DISABLED
// Enable SPI
// MSB data order
// Master select
// Clock polarity rising
// Clock phashe - default
// Clock divider
// Data order = 0 (MSB first)
//SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (1<<CPOL) | (1<<CPHA) | (0<<SPR1) | (0<<SPR0); // 1/2 mode=3 âðîäå ÎÊ íî íå ðàáîëòàåò
//SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (1<<SPR0); // 1/8 mode=0 âðîäå OK íî íå ðàáîòàåò
//SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (1<<CPHA) | (1<<SPR1) | (1<<SPR0); // 1/16 mode=1 ÍÅ ÐÀÁÎÒÀÅÒ!!!
//SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (1<<CPOL) | (0<<CPHA) | (1<<SPR1) | (1<<SPR0); // 1/16 mode=2 ÍÅ ÐÀÁÎÒÀÅÒ!!!
SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (1<<SPR1) | (1<<SPR0); // 1/16 mode=0 âðîäå OK íî íå ðàáîòàåò
// Port A initialization
// PA7=LED PA6=IN.EXT4.2 PA5=IN3 PA4=IN4 PA3=IN5 PA2=IN6 PA1=In7 PA0=IN8
// Out TriS TriS TriS TriS TriS TriS TriS
PORTA = 0b00000000;
DDRA = 0b10000000;
// Port C initialization
// PC7=EXT4.1 PC6=EXT4.2 PC5=EXT4.5 PC4=EXT4.6 PC3=PWRKEY PC2=Ext2.2 PC1=Ext2.3 PC0=Ext2.4
// Tri Tri Tri Tri Out Out Out Out
PORTC = 0b00000000;
DDRC = 0b00001111;
RST_HIGH();
}
/**
* Writes a byte to the specified register in the MFRC522 chip.
* The interface is described in the datasheet section 8.1.2.
*/
void PCD_WriteRegister(unsigned char reg, ///< The register to write to. One of the PCD_Register enums.
unsigned char value) ///< The value to write.
{
CS_LOW(); // Select slave
SPI_transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3.
SPI_transfer(value);
CS_HIGH(); // Release slave again
}
/**
* Writes a number of bytes to the specified register in the MFRC522 chip.
* The interface is described in the datasheet section 8.1.2.
*/
void PCD_WriteRegisterScope(unsigned char reg, ///< The register to write to. One of the PCD_Register enums.
unsigned char count, ///< The number of bytes to write to the register
unsigned char *values) ///< The values to write. Byte array.
{
CS_LOW(); // Select slave
SPI_transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3.
for (unsigned char index = 0; index < count; index++) {
SPI_transfer(values[index]);
}
CS_HIGH(); // Release slave again
}
/**
* Reads a byte from the specified register in the MFRC522 chip.
* The interface is described in the datasheet section 8.1.2.
*/
unsigned char PCD_ReadRegister(unsigned char reg) ///< The register to read from. One of the PCD_Register enums.
{
unsigned char value;
CS_LOW(); // Select slave
SPI_transfer(0x80 | (reg & 0x7E)); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
value = SPI_transfer(0); // Read the value back. Send 0 to stop reading.
CS_HIGH(); // Release slave again
return value;
}
/**
* Reads a number of bytes from the specified register in the MFRC522 chip.
* The interface is described in the datasheet section 8.1.2.
*/
void PCD_ReadRegisterScope(unsigned char reg, ///< The register to read from. One of the PCD_Register enums.
unsigned char count, ///< The number of bytes to read
unsigned char *values, ///< Byte array to store the values in.
unsigned char rxAlign) ///< Only bit positions rxAlign..7 in values[0] are updated.
{
if (count == 0) {
return;
}
//Serial.print("Reading "); Serial.print(count); Serial.println(" bytes from register.");
unsigned char address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
unsigned char index = 0; // Index in values array.
CS_LOW(); // Select slave
count--; // One read is performed outside of the loop
SPI_transfer(address); // Tell MFRC522 which address we want to read
while (index < count) {
if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0]
// Create bit mask for bit positions rxAlign..7
unsigned char mask = 0;
for (unsigned char i = rxAlign; i <= 7; i++) {
mask |= (1 << i);
}
// Read value and tell that we want to read the same address again.
unsigned char value = SPI_transfer(address);
// Apply mask to both current value of values[0] and the new data in value.
values[0] = (values[index] & ~mask) | (value & mask);
}
else { // Normal case
values[index] = SPI_transfer(address); // Read value and tell that we want to read the same address again.
}
index++;
}
values[index] = SPI_transfer(0); // Read the final byte. Send 0 to stop reading.
CS_HIGH(); // Release slave again
}
/**
* Sets the bits given in mask in register reg.
*/
void PCD_SetRegisterBitMask(unsigned char reg, ///< The register to update. One of the PCD_Register enums.
unsigned char mask) ///< The bits to set.
{
unsigned char tmp;
tmp = PCD_ReadRegister(reg);
PCD_WriteRegister(reg, tmp | mask); // set bit mask
}
/**
* Clears the bits given in mask from register reg.
*/
void PCD_ClearRegisterBitMask(unsigned char reg, ///< The register to update. One of the PCD_Register enums.
unsigned char mask) ///< The bits to clear.
{
unsigned char tmp;
tmp = PCD_ReadRegister(reg);
PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask
}
/**
* Turns the antenna on by enabling pins TX1 and TX2.
* After a reset these pins disabled.
*/
void PCD_AntennaOn()
{
unsigned char value = PCD_ReadRegister(TxControlReg);
if ((value & 0x03) != 0x03)
{
PCD_WriteRegister(TxControlReg, value | 0x03);
}
}
void PCD_Reset()
{
PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command.
// The datasheet does not mention how long the SoftRest command takes to complete.
// But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg)
// Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74?s. Let us be generous: 50ms.
delay(50);
// Wait for the PowerDown bit in CommandReg to be cleared
while (PCD_ReadRegister(CommandReg) & (1<<4))
{
// PCD still restarting - unlikely after waiting 50ms, but better safe than sorry.
}
} // End PCD_Reset()
/**
* Transfers data to the MFRC522 FIFO, executes a commend, waits for completion and transfers data back from the FIFO.
* CRC validation can only be done if backData and backLen are specified.
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
unsigned char PCD_CommunicateWithPICC(unsigned char command, ///< The command to execute. One of the PCD_Command enums.
unsigned char waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command.
unsigned char *sendData, ///< Pointer to the data to transfer to the FIFO.
unsigned char sendLen, ///< Number of bytes to transfer to the FIFO.
unsigned char *backData, ///< NULL or pointer to buffer if data should be read back after executing the command.
unsigned char *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned.
unsigned char *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits.
unsigned char rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0.
unsigned char checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated.
) {
unsigned char n, _validBits;
unsigned int i;
// Prepare values for BitFramingReg
unsigned char txLastBits = validBits ? *validBits : 0;
unsigned char bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command.
PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits
PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization
PCD_WriteRegisterScope(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO
PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments
PCD_WriteRegister(CommandReg, command); // Execute the command
if (command == PCD_Transceive) {
PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts
}
// Wait for the command to complete.
// In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting.
// Each iteration of the do-while-loop takes 17.86?s.
i = 2000;
while (1) {
n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq
if (n & waitIRq) { // One of the interrupts that signal success has been set.
break;
}
if (n & 0x01)
{ // Timer interrupt - nothing received in 25ms
putchr('1');
return STATUS_TIMEOUT;
}
if (--i == 0)
{ // The emergency break. If all other condions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down.
putchr('2');
return STATUS_TIMEOUT;
}
}
// Stop now if any errors except collisions were detected.
unsigned char errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr
if (errorRegValue & 0x13)
{ // BufferOvfl ParityErr ProtocolErr
putchr('e');
return STATUS_ERROR;
}
// If the caller wants data back, get it from the MFRC522.
if (backData && backLen) {
n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO
if (n > *backLen) {
putchr('r');
return STATUS_NO_ROOM;
}
*backLen = n; // Number of bytes returned
PCD_ReadRegisterScope(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO
_validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid.
if (validBits) {
*validBits = _validBits;
}
}
// Tell about collisions
if (errorRegValue & 0x08) { // CollErr
putchr('c');
return STATUS_COLLISION;
}
/*
// Perform CRC_A validation if requested.
if (backData && backLen && checkCRC) {
// In this case a MIFARE Classic NAK is not OK.
if (*backLen == 1 && _validBits == 4) {
return STATUS_MIFARE_NACK;
}
// We need at least the CRC_A value and all 8 bits of the last byte must be received.
if (*backLen < 2 || _validBits != 0) {
return STATUS_CRC_WRONG;
}
// Verify CRC_A - do our own calculation and store the control in controlBuffer.
unsigned char controlBuffer[2];
n = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]);
if (n != STATUS_OK) {
return n;
}
if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) {
return STATUS_CRC_WRONG;
}
}
*/
putchr('o');
return STATUS_OK;
}
/**
* Executes the Transceive command.
* CRC validation can only be done if backData and backLen are specified.
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
unsigned char PCD_TransceiveData(unsigned char *sendData, ///< Pointer to the data to transfer to the FIFO.
unsigned char sendLen, ///< Number of bytes to transfer to the FIFO.
unsigned char *backData, ///< NULL or pointer to buffer if data should be read back after executing the command.
unsigned char *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned.
unsigned char *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL.
unsigned char rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0.
unsigned char checkCRC) ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated.
{
unsigned char waitIRq = 0x30; // RxIRq and IdleIRq
return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC);
}
/**
* Transmits REQA or WUPA commands.
* Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
unsigned char PICC_REQA_or_WUPA(unsigned char command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA
unsigned char *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in
unsigned char *bufferSize) ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
{
unsigned char validBits;
unsigned char status;
if (bufferATQA == NULL || *bufferSize < 2) { // The ATQA response is 2 bytes long.
return STATUS_NO_ROOM;
}
PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared.
validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0]
status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits, 0,0);
if (status != STATUS_OK) {
return status;
}
if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits.
return STATUS_ERROR;
}
return STATUS_OK;
}
/**
* Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
* Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
unsigned char PICC_RequestA(unsigned char *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in
unsigned char *bufferSize) ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
{
return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize);
}
void PCD_Init()
{
RST_LOW();
_delay_ms(200);
RST_HIGH();
_delay_ms(200);
//if (digitalRead(_resetPowerDownPin) == LOW)
//{ //The MFRC522 chip is in power down mode.
// digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset.
// // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74?s. Let us be generous: 50ms.
// delay(50);
//}
//else { // Perform a soft reset
PCD_Reset();
//}
_delay_ms(200);
// When communicating with a PICC we need a timeout if something goes wrong.
// f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo].
// TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg.
PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds
PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25?s.
PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout.
PCD_WriteRegister(TReloadRegL, 0xE8);
PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4)
PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset)
} // End PCD_Init()
unsigned char PICC_IsNewCardPresent()
{
unsigned char ret;
unsigned char bufferATQA[2];
unsigned char bufferSize = sizeof(bufferATQA);
unsigned char result = PICC_RequestA(bufferATQA, &bufferSize);
if (result == STATUS_OK || result == STATUS_COLLISION)
ret = 1;
else
ret = 0;
return ret;
}
void rfid_test()
{
unsigned char i;
rfid_spi_init();
Init_UART9600();
Send_UART("rfid_test\r\n");
_delay_ms(300);
PCD_Init();
Send_UART("Ver = ");
for (i=0;i<5;i++)
{
unsigned char Ver;
Ver = PCD_ReadRegister(VersionReg);
Print_Byte(Ver);
putchr(' ');
}
Send_UART("\r\n");
_delay_ms(2000);
while(1)
{
if (PICC_IsNewCardPresent())
{
Send_UART("NewCard\r\n");
}
putchr(' ');
}
}
Сообщение отредактировал Mad-man - Jun 2 2014, 09:10