NFC PN532 on Teensy 3.5 - nfc

I have a problem with my teensy 3.5 for reading NFC tag using a PN532 :
I am using the Adafruit_PN532 librairie.
here is my wiring :
PN532 | Teensy 3.5
------------------
5V -> Vin
GND -> Gnd
SCK -> 13
MISO -> 39
MOSI -> 28
SS -> 10
And my code :
/**************************************************************************/
/*!
#file readMifare.pde
#author Adafruit Industries
#license BSD (see license.txt)
This example will wait for any ISO14443A card or tag, and
depending on the size of the UID will attempt to read from it.
If the card has a 4-byte UID it is probably a Mifare
Classic card, and the following steps are taken:
- Authenticate block 4 (the first block of Sector 1) using
the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
- If authentication succeeds, we can then read any of the
4 blocks in that sector (though only block 4 is read here)
If the card has a 7-byte UID it is probably a Mifare
Ultralight card, and the 4 byte pages can be read directly.
Page 4 is read by default since this is the first 'general-
purpose' page on the tags.
This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
This library works with the Adafruit NFC breakout
----> https://www.adafruit.com/products/364
Check out the links above for our tutorials and wiring diagrams
These chips use SPI or I2C to communicate.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
*/
/**************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>
// If using the breakout with SPI, define the pins for SPI communication.
#define PN532_SCK (13)
#define PN532_MOSI (28)
#define PN532_SS (10)
#define PN532_MISO (39)
// If using the breakout or shield with I2C, define just the pins connected
// to the IRQ and reset lines. Use the values below (2, 3) for the shield!
//#define PN532_IRQ (2)
//#define PN532_RESET (3) // Not connected by default on the NFC Shield
// Uncomment just _one_ line below depending on how your breakout or shield
// is connected to the Arduino:
// Use this line for a breakout with a software SPI connection (recommended):
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
// Use this line for a breakout with a hardware SPI connection. Note that
// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's
// hardware SPI SCK, MOSI, and MISO pins. On an Arduino Uno these are
// SCK = 13, MOSI = 11, MISO = 12. The SS line can be any digital IO pin.
//Adafruit_PN532 nfc(PN532_SS);
// Or use this line for a breakout or shield with an I2C connection:
//Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
void setup(void) {
delay(1000);
Serial.begin(115200);
Serial.println("Hello!");
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A Card ...");
}
void loop(void) {
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (success) {
// Display some basic information about the card
Serial.println("Found an ISO14443A card");
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print(" UID Value: ");
nfc.PrintHex(uid, uidLength);
Serial.println("");
if (uidLength == 4)
{
// We probably have a Mifare Classic card ...
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
// Now we need to try to authenticate it for read/write access
// Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
Serial.println("Trying to authenticate block 4 with default KEYA value");
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// Start with block 4 (the first block of sector 1) since sector 0
// contains the manufacturer data and it's probably better just
// to leave it alone unless you know what you're doing
success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
if (success)
{
Serial.println("Sector 1 (Blocks 4..7) has been authenticated");
uint8_t data[16];
// If you want to write something to block 4 to test with, uncomment
// the following line and this text should be read back in a minute
//memcpy(data, (const uint8_t[]){ 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0 }, sizeof data);
// success = nfc.mifareclassic_WriteDataBlock (4, data);
// Try to read the contents of block 4
success = nfc.mifareclassic_ReadDataBlock(4, data);
if (success)
{
// Data seems to have been read ... spit it out
Serial.println("Reading Block 4:");
nfc.PrintHexChar(data, 16);
Serial.println("");
// Wait a bit before reading the card again
delay(1000);
}
else
{
Serial.println("Ooops ... unable to read the requested block. Try another key?");
}
}
else
{
Serial.println("Ooops ... authentication failed: Try another key?");
}
}
if (uidLength == 7)
{
// We probably have a Mifare Ultralight card ...
Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");
// Try to read the first general-purpose user page (#4)
Serial.println("Reading page 4");
uint8_t data[32];
success = nfc.mifareultralight_ReadPage (4, data);
if (success)
{
// Data seems to have been read ... spit it out
nfc.PrintHexChar(data, 4);
Serial.println("");
// Wait a bit before reading the card again
delay(1000);
}
else
{
Serial.println("Ooops ... unable to read the requested page!?");
}
}
}
}
But when I run my code I have that output :
Hello!
Didn't find PN53x board
I have also slide the switches to the SPI mode. Like that :
I don't kwow why my teensy does not find my board...
Hope someone have a solution :).
Thank you for reading me.

Related

Slave ESP32 send back wrong data to master esp32

I am currently trying to implement an SPI communication between 2 ESP32 using arduino IDE but i am facing a problem.
I set 1 as a master using the normal SPI library and the second one as slave using ESP32SPISlave.
Master SW is basically writing 0 or 1 to slave device and wait for a response
if the master send a 0 the slave will send back 2 in the next communication,
if the master send 1 the slave will send back 1 in the next communication.
the problem that sometimes even if the master send 1 i receive the number 2 instead of 1 so it seems that it doesn't override the previous value.
I am not sure exactly what's the problem. could you please support me?
I will paste both SW
You can find the picture of the issue in the link below
https://drive.google.com/file/d/1K08ntvOcR7fH9SyWb-RZu7XXCOKP2msH/view?usp=sharing
Master SW
#include <SPI.h>
// Define ALTERNATE_PINS to use non-standard GPIO pins for SPI bus
#ifdef ALTERNATE_PINS
#define VSPI_MISO 26
#define VSPI_MOSI 27
#define VSPI_SCLK 25
#define VSPI_SS 32
#else
#define VSPI_MISO MISO
#define VSPI_MOSI MOSI
#define VSPI_SCLK SCK
#define VSPI_SS SS
#endif
static const int spiClk = 1000000; // 1 MHz
int data1;
//uninitalised pointers to SPI objects
SPIClass * vspi = NULL;
void setup() {
Serial.begin(115200);
delay(2000);
//initialise instance of the SPIClass attached to HSPI
vspi = new SPIClass(VSPI);
//clock miso mosi ss
#ifndef ALTERNATE_PINS
//initialise hspi with default pins
//SCLK = 14, MISO = 12, MOSI = 13, SS = 15
vspi->begin();
#else
//alternatively route through GPIO pins
vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS
#endif
//set up slave select pins as outputs as the Arduino API
//doesn't handle automatically pulling SS low
pinMode(VSPI_SS, OUTPUT); //HSPI SS
}
// the loop function runs over and over again until power down or reset
void loop() {
vspi_send_command();
delay(1000);
}
void vspi_send_command() {
byte data_on = 0b00000001; // data 1 to turn on LED of slave
byte data_off = 0b0000000; // data 0 to turn off LED of slave
vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
digitalWrite(VSPI_SS, LOW);
data1 = vspi->transfer(data_on);
digitalWrite(VSPI_SS, HIGH);
vspi->endTransaction();
Serial.print("data sent is 1 and data received is ");
Serial.println(data1);
delay(1000);
vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
digitalWrite(VSPI_SS, LOW);
data1 = vspi->transfer(data_off);
digitalWrite(VSPI_SS, HIGH);
vspi->endTransaction();
Serial.print("data sent is 0 and data received is ");
Serial.println(data1);
delay(1000);
}
Slave SW
#include <ESP32SPISlave.h>
ESP32SPISlave slave;
static constexpr uint32_t BUFFER_SIZE {32};
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];
#define LED 2
void setup() {
Serial.begin(115200);
delay(2000);
pinMode(LED, OUTPUT);
// begin() after setting
// HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> default
// VSPI = CS: 5, CLK: 18, MOSI: 23, MISO: 19
slave.setDataMode(SPI_MODE0);
//slave.begin();
slave.begin(VSPI); // you can use VSPI like this
// clear buffers
memset(spi_slave_tx_buf, 0, BUFFER_SIZE);
memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}
void loop() {
// block until the transaction comes from master
slave.wait(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
// if transaction has completed from master,
// available() returns size of results of transaction,
// and buffer is automatically updated
char data;
while (slave.available()) {
// show received data
Serial.print("Command Received: ");
Serial.println(spi_slave_rx_buf[0]);
data = spi_slave_rx_buf[0];
slave.pop();
}
if(data == 1 )
{
Serial.println("Setting LED active HIGH ");
digitalWrite(LED, HIGH);
memset(spi_slave_tx_buf, 1, BUFFER_SIZE);
}
else if(data == 0 )
{
Serial.println("Setting LED active LOW ");
digitalWrite(LED, LOW);
memset(spi_slave_tx_buf, 2, BUFFER_SIZE);
}
Serial.println("");
}
Thank you again for your cooperation.
SPI is a very specific interface and slave can only transmit if the master transmits.
If your slave starts to send a data based on what has been received from the master, then you only get the data from the slave on the 2nd transmission of your master transmission. That is, you need to send two bytes of data from the master, the first byte is the data you want the slave to receive, the second byte is a dummy in order to clock-in the received data.

UART program for PIC18f65k40

I'm trying to program my MCU in mickroc still I do not get a output.
Is there any difference between PIC18f65k40 and PIC18f65k22 in terms of initiating uart transmission? Whether there is any need to initiate or disable any special registers in PIC18f65k40?
In mikroc software there present a library for uart so I just copied the program from mickroe website and add my transmitter and receiver pins(RX4PPS = 0x11; and TX4PPS = 0x10;)in program by configuring portc as output but my circuit does not work.
char i ;
void main()
{
TRISC = 0b00000000;// making port as output
RX4PPS = 0x11;
TX4PPS = 0x10;
UART4_Init(9600); // Initialize USART module
// (8 bit, 9600 baud rate, no parity bit...)
delay_ms(500);
UART4_Write_Text("Hello world!");
UART4_Write(13); // Start a new line
UART4_Write(10);
UART4_Write_Text("PIC18F65K40 UART example");
UART4_Write(13); // Start a new line
UART4_Write(10);
while (1) {
if (UART4_Data_Ready()) { // If data has been received
i = UART4_Read(); // read it
UART4_Write(i); // and send it back
}
}
}
The PIC18F65k22 has only 2 UARTs and you are working with UART4. I guess the library don't support the controller. Better write the code on your own. There are some examples in the datasheet.

How do I read passive NFC/RFID units with PN532?

I got the little red "ELECHOUSE V3" kit off of eBay with a white card, and a blue keyfob transponder, and I've written a C program which creates and decodes packets and I can send it commands and it responds with AC packets, and I can read the version and the status. I'm not using any RFID library, I'm just using plain C and making my own simple library because I want to understand it and I want to release a simple single file demonstration for people who really want to understand it rather than just using some arduino lib or whatever. So that's all the questions I'm not asking.
So here's the question I am asking:
What is the exact commands to send to scan for the presence of passive (non powered) transponders? I do not know for sure what kind they are, but they came with the kit and are probably ISO 14443 / 14443A.
Actually, I tried the tags on my Samsung Galaxy S4, and it says they are ISO 14443-3A NXP MIFARE Classic 1K - Not Supported. But it still shows the serial numbers for them.
What are the exact commands to scan for all supported card types?
To send a command I use my function like this:
sendcmd("0x4A 0x01 0x00");
(The TFI of 0xD4 is automatically added to the commands, and the preamble/len/lcs/checksums are all calculated and dealt with.)
I do get ACKS back for my commands, but can't figure out which commands to send to scan for cards or read them.
If I can get the PN532 to spit card scan data back at me I should be able to parse it using the PN532 datasheet.
Thank you very much,
Jesse
Ahh OK.. After trying everything that seemed related indicated in the data sheet with no success, I turned ham radio on to 13.56Mhz CW/LSB and there was nothing to be heard.. So just for kicks I tried the RFRegulationTest command, and that unlocked the whole thing! Seems to be a test command which turns on the transmitter and leaves it on till you issue another command... But it initializes something as needed!
So here's the commands it takes to make the NXP NP532 scan for cards:
(I'm using RS232 at 115200bps, but should be similar for other interfaces.)
You send to it:
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0xFF 0x03 0xFD 0xD4 0x58 0x00 0xD4
and you'll get an ACK and transmitter will key on:
0x00 0x00 0xFF 0x00 0xFF 0x00
And at this point the transmitter will key up. Maybe let it do that for 100mS or something, then you can start scanning for cards:
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0xFF 0x04 0xFC 0xD4 0x4A 0x02 0x00 0xE0
The chip will then turn on the radio transmitter and start scanning for cards until a card comes in range, then it reads the serial number, shuts down the transmitter, and gives you a packet which contains:
0x4B, 0x01/0x02 (Depending on whether 1 or 2 cards was detected), followed by various info about the card like it's serial number.
You can also set the max number of tries it'll try when given the 0x4A 0x02 0x00 command, by setting the number of tries to a number below 0xFF, like this:
sendcmd("0x32 0x05 0xFF 0x01 0x10")
in which case when you give the read command (0x4A 0x02 0x00) it'll try for a fraction of a second (0x10 times) then give up and send a packet that contains:
0x4B, 0x00
which means "Cards found: Zero."
See the datasheet for all the details, it does tell you everything you need to know, except I never could figure out how to enable the transmitter until I ran the rf test command.
Anyway, just keep sending the second command over and over a few times a second or slower if you like, and each time you send that command it will scan and let you know if there is a card within range!
Or if you set retries to 0xFF then it'll try forever until it detects a card, then you only have to re-send the scan-for-card command when it finds one.
The long strings of 0xFF is just to wake the device up because it goes to sleep and misses the first few bytes you send.
The examples I give of what to send it that start with a bunch of 0xFF's are the whole full packet, including preambles, length field, checksums and everything calculated. You can send them directly to make it scan for cards.
The initial RF test command and the retry set command only needs to be run once on powerup, after that just keep re-sending the read command as needed.
My PN532 chip reports itself as Version: 1.6
Here's my little sample program:
(The RS232 initialization part I lifted from an SO post - thanks to whoever wrote that!)
(It's for Linux. Compile with gcc nfc.c -o nfc.e )
(Should be able to port it to any platform, you just have to deal with the serial port - the rest is platform independent.)
(Also note that this simply scans for cards and returns serial number/NFCID, and only for Mifare, ISO/IEC14443-3 Type A cards at 106kbps in passive mode. If you want to actually read/write to the memory on the cards, you have to write more code, but this at least demonstrates what it takes to get started and how the command structure works, and provides some handy routines for sending and decoding packets.)
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int debug=0;
int fd;
void init_rs232(void);
void sendpacket(unsigned char * payload, int len);
void sendcmd(char * payload);
int main(void)
{
printf("Welcome!\n");
init_rs232();
int waitfor;
#define PACKET 1
#define ACK 2
sendcmd("0x58 0x00");waitfor=ACK; //RFRegulationTest -- This command is used for radio regulation test.
int cstate=0; //Chat state, config state, whatever..
int lc=0;
while(1)
{
lc++; //Send a scan command every second or so.
if(lc>1000)
{
lc=0;
sendcmd("0x4A 0x02 0x00"); //InListPassiveTarget -- The goal of this command is to detect as many targets (maximum MaxTg) as possible (max two) in passive mode.
}
if(cstate==1) //ACK's set the bottom bit in state, allowing it to go onto the next state.
{
sendcmd("0x02");waitfor=PACKET; //Read the version out of the PN532 chip.
cstate++;
}
if(cstate==3) //ACK's set the bottom bit in state, allowing it to go onto the next state.
{
sendcmd("0x04");waitfor=PACKET; //Get current status.
cstate++;
}
if(cstate==5)
{
waitfor=PACKET;
sendcmd("0x32 0x05 0xFF 0x01 0x10");//Max retries - last byte is for passive: 0=1 try, 1=2 tries, 254=255 tries, 0xFF=infinite retries.
//If last byte is 0xFF, then unit starts scanning for cards indefinitely. As soon as it detects a card, it stops scanning and returns info.
//If last byte is less than 0xFF, it tries scans and as soon as it finds a card returns info on it and stops trying, but
//if it never finds a card in the specified number of retries, it gives up and returns 0x4B, 0x00 (Cards found: Zero.)
cstate++;
}
//Alternative way to send a new scan command each time the previous one gives up or finds a card:
// if(cstate==7)
// {
// waitfor=PACKET;
// sendcmd("0x4A 0x02 0x00"); //InListPassiveTarget
// cstate--;
// }
static unsigned char buffin [1000024];
static unsigned char buf[1],bufo[1];
int n;
static int bi=0;
unsigned char len,lcs,tfi,dcs;
bufo[0]=buf[0];
n=read(fd,buf,sizeof(buf));
if(n!=0)
{
if(n>0)
{
if(bi<1000000)
{
static int state=0;
if(state==0) //Waiting for preamble..
{
if((bufo[0]==0)&&(buf[0]==0xFF)){state=10;}
}
else if(state==10) //Waiting for Len
{
len=buf[0];
state=20;
}
else if(state==20) //Waiting for len checksum
{
if((len==0xFF)&&(buf[0]==0xFF)){printf("ERROR: BIG PACKET. Bye.\n");exit(-2);}
if((len==0x00)&&(buf[0]==0xFF)){state=21;}
else if((len==0xFF)&&(buf[0]==0x00)){state=21;}
else
{
lcs=buf[0]+len;
if(lcs){printf("ERROR: len checksum failed! 0x%02X\n",buf[0]);}
state=30;
}
}
else if(state==21) //Waiting for the 0x00 after ack/nack..
{
state=0;
if(buf[0]==0x00)
{
if(bufo[0]==0xFF)
{
if(debug){printf("ACK!\n");}
if(waitfor==ACK){cstate=cstate|1;}
}
if(bufo[0]==0x00){printf("NACK!\n");}
}else{
printf("ERROR: Invalid length, or ack/nack missing postamble...\n");
}
}
else if(state==30) //Waiting for tfi..
{
tfi=buf[0];
//printf("tfi=0x%02X\n",tfi);
dcs=tfi;
bi=0;
state=40;
}
else if(state==40) //Saving bytes...
{
//printf("Saving payload byte 0x%02X\n",buf[0]);
buffin[bi++]=buf[0];
dcs=dcs+buf[0];
if(bi>=len){state=50;}
}
else if(state==50) //Calculating the checksum..
{
state=0;
dcs=dcs+buf[0];
if(dcs)
{
printf("ERROR: Data Checksum Failed! (0x%02X)\n",dcs);
}else{
if(waitfor==PACKET){cstate=cstate|1;}
//printf("Good Packet: tfi=0x%02X, len=%d\n",tfi,len-1);
if(tfi==0xD5)
{
if(buffin[0]==0x03){printf("PN532 Version: %d.%d, features:%d\n",buffin[2],buffin[3],buffin[4]);}
if(buffin[0]==0x05)
{
printf("Status: Last Error:%d, Field:%d, Targets:%d, SAM Status:0x%02X\n",buffin[1],buffin[2],buffin[3],buffin[len-2]);
static char bitrates[255][10]={"106kbps","212kbps","424kbps"};
static char modtypes[255][100];
strcpy(modtypes[0x00],"Mifare, ISO/IEC14443-3 Type A, ISO/IEC14443-3 Type B, ISO/IEC18092 passive 106 kbps");
strcpy(modtypes[0x10],"FeliCa, ISO/IEC18092 passive 212/424 kbps");
strcpy(modtypes[0x01],"ISO/IEC18092 Active mode");
strcpy(modtypes[0x02],"Innovision Jewel tag");
if(buffin[3]==1){printf("Target %d: rx bps:%s, tx bps:%s, modulation type: %s.\n",buffin[4],bitrates[buffin[5]],bitrates[buffin[6]],modtypes[buffin[7]]);}
if(buffin[3]==2){printf("Target %d: rx bps:%s, tx bps:%s, modulation type: %s.\n",buffin[8],bitrates[buffin[9]],bitrates[buffin[10]],modtypes[buffin[11]]);}
}
if(buffin[0]==0x4B)
{
printf("FOUND %d CARDS!\n",buffin[1]);
//ONLY VALID FOR Mifare/ ISO type A 106KBPS:
int i,ii,iii;
i=0;ii=2;
while(i<buffin[1])
{
printf("Target # %d:", buffin[ii++]);
printf("SENS_RES=0x%02X%02X, ",buffin[ii],buffin[ii+1]);ii++;ii++;
printf("SEL_RES=0x%02X, ",buffin[ii++]);
printf("NFCIDLength=%d, ",buffin[ii++]);
printf("NFCID=");
iii=0;
while(iii<buffin[ii-1])
{
printf("%02X",buffin[ii+iii]);
iii++;
if(iii<buffin[ii-1]){printf(":");}
}
ii=ii+iii;
printf("\n");
i++;
}
}
//Just a debugging thing for printing out the contents of valid packets.
//int i=0;while(i<(len-1)){printf("0x%02X, ",buffin[i++]);}printf("\n");
}
else if(tfi==0x7F)
{
printf("Received error packet 0x7F with zero size.\n");
}else{
printf("ERROR: Got unknown %d byte packet with tfi=0x%02X!\n",len-1,tfi);
}
}
}
else
{
printf("Uhoh!\n");
}
//printf("Got byte 0x%02X, now state is %d\n",(unsigned char)buf[0],state);
}else{
printf("ERROR: bi=%d which is too big.. Starting over.\n",bi);
bi=0;
}
}else{
printf("ERROR %d while reading serial port: %s\n",errno,strerror(errno));
exit(-1);
}
}
usleep(1000);
}
return(0);
}
void init_rs232(void)
{
char *portname = "/dev/ttyUSB0";
fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
printf("error %d opening %s: %s", errno, portname, strerror (errno));
exit(-1);
}
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
printf("error %d from tcgetattr(%s)\n", errno,strerror(errno));
exit(-1);
}
cfsetospeed (&tty, B115200);
cfsetispeed (&tty, B115200);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 0; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= 0; //This was parity
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
printf("error %d from tcsetattr(%s)\n", errno,strerror(errno));
exit(-1);
}
}
void sendpacket(unsigned char * payload, int len)
{
int tfi;
static unsigned char buffer[66000];
int i,bo;
unsigned char lcs,dcs;
tfi=0xD4;
i=0;
bo=0;
while(i<=8){i++;buffer[bo++]=0xFF;} //Pre-padding.. 8-800 OK, 900 too much, 7 too little. Needs to be 0xFF I guess.. Probably wakes it up.
buffer[bo++]=0x00; //Preamble.
buffer[bo++]=0xFF; //Preamble.
len++;
lcs=-len; //Length Checksum.. (yes...)
buffer[bo++]=len;
buffer[bo++]=lcs;
buffer[bo++]=tfi;
dcs=tfi;
i=0;
while((i<65900)&&(i<(len-1)))
{
buffer[bo]=payload[i];
dcs=dcs+buffer[bo];
bo++;
i++;
}
dcs=(-dcs);
buffer[bo++]=dcs;
write(fd,buffer,bo);
//printf("Sent %d bytes\n",bo);
//printf("Whole packet: ");
//i=0;
//while(i<bo)
//{
// printf("0x%02X ",buffer[i]);
// i++;
//}
//printf("\n");
}
void sendcmd(char * payload) //Accepts space separated argument list like "0xFF 0x0A 255 'USERID' 0 0"
{ //strings are quoted in half quotes. half quotes inside a string are escaped \\'
int i,v; //full quotes inside a string are escaped like \"
static unsigned char buffer[1024]; //back slashes inside a string are escaped like \\\\ .
static int bo; //(The first escape or escape pair is for the C compiler, the second for this function:
bo=0; // The actual contents of the string are just \' and \\)
i=0; // Numeric formats supported are hex (0xNN), base ten (123), and octal (0377).
if(debug){printf("sendcmd: ");}
while(payload[i])
{
if((payload[i]!='\'')&&(payload[i]!=' '))
{
v=strtoul(&payload[i],NULL,0);
buffer[bo++]=v;
if(debug){printf("0x%02X, ",v);}
while(payload[i]>' '){i++;}
}
else if(payload[i]=='\'')
{
i++;
int keeprun;
keeprun=1;
while(keeprun)
{
if(payload[i]=='\\')
{
i++;
}else{
if(payload[i]=='\''){keeprun=0;}
}
if((keeprun)&&(payload[i]))
{
buffer[bo++]=payload[i];
if(debug){printf("%c",payload[i]);}
}
i++;
}
if(debug){printf(", ");}
}
else
{
i++;
}
}
if(debug){printf("\n");}
sendpacket(buffer,bo);
}

Arduino/MPU6050/AdafruitMotorShieldV2: script hangs/freezes when turn on motors

I'm a newby to robotics and electronics in general, so please don't assume I tried anything you might think is obvious.
I'm trying to create a cart which will basically run around by itself (simple AI routines to avoid obstacles, go from pt. A to pt. B around corners, follow lines, etc.). I'm putting together an Adafruit Arduino Uno R3 with the Adafruit Motor Shield v2 and an MPU-6050. I'm using the "breadboard" on the Motor Shield for the circuitry, soldering everything there.
I can get all the pieces working independently with their own scripts: the Motor Shield drives the 4 motors as expected using the Adafruit library; I'm using the "JRowberg" library for the MPU-6050, and started with the example MPU6050_DMP6.ino, which works fine as long as the cart motors are turned off. My only changes in the example script below are motor startup and some simple motor commands.
As long as I leave the switch which powers the motors off, everything seems fine: it outputs to the Serial window continuously with Euler data which, I assume, is correct. However, a few seconds after I turn on the power to the motors (and the wheels start turning), it just hangs/freezes: the output to the Serial window stops (sometimes in mid-line), and the wheels keep turning at the speed of their last change. Sometimes I see "FIFO overflow" errors, but not always. Sometimes I see "nan" for some of the floating point values before it hangs, but not always.
Some things I've tried, all of which changed noting:
* I've swapped out the MPU-6050 board for another from the same manufacturer.
* I've tried moving the MPU-6050 away from the motors using a ribbon cable.
* I've changed the I2C clock using JRowber's advice (a change in a .h file and changing the value of the TWBR variable), but I don't think I've tried all possible values.
* I've changed the speed of the MotorShield in the AFMS.begin() command, although, again, there are probably other values I haven't tried, and I'm not sure how in-sync this and the TWBR value need to be.
And some other things, all to no avail.
Below is an example script which fails for me:
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#include "Adafruit_MotorShield.h"
#include "utility/Adafruit_PWMServoDriver.h"
#define DEBUG 1
MPU6050 mpu;
#define OUTPUT_READABLE_EULER
#define LED_PIN 13
bool blinkState = false;
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
#define NUM_MOTORS 4
#define MOTOR_FL 0
#define MOTOR_FR 1
#define MOTOR_RR 2
#define MOTOR_RL 3
Adafruit_DCMotor *myMotors[NUM_MOTORS] = {
AFMS.getMotor(1),
AFMS.getMotor(2),
AFMS.getMotor(3),
AFMS.getMotor(4),
};
#define CHANGE_SPEED_TIME 500
long changeSpeedMillis = 0;
int curSpeed = 30;
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
void setup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// start the motor shield.
AFMS.begin(); // create with the default frequency 1.6KHz
// AFMS.begin(4000); // OR with a different frequency, say 4KHz
// kill all the motors.
myMotors[MOTOR_FL]->run(BRAKE);
myMotors[MOTOR_FL]->setSpeed(0);
myMotors[MOTOR_FR]->run(BRAKE);
myMotors[MOTOR_FR]->setSpeed(0);
myMotors[MOTOR_RR]->run(BRAKE);
myMotors[MOTOR_RR]->setSpeed(0);
myMotors[MOTOR_RL]->run(BRAKE);
myMotors[MOTOR_RL]->setSpeed(0);
Serial.println("Motor Shield ready!");
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
// as per Vulpo's post.
delay(10);
if (millis() > changeSpeedMillis) {
curSpeed += 20;
if (curSpeed > 256) {
curSpeed = 30;
}
Serial.print("changing speed to: ");
Serial.println(curSpeed);
myMotors[MOTOR_FL]->run(FORWARD);
myMotors[MOTOR_FL]->setSpeed(curSpeed);
myMotors[MOTOR_FR]->run(FORWARD);
myMotors[MOTOR_FR]->setSpeed(curSpeed);
myMotors[MOTOR_RR]->run(FORWARD);
myMotors[MOTOR_RR]->setSpeed(curSpeed);
myMotors[MOTOR_RL]->run(FORWARD);
myMotors[MOTOR_RL]->setSpeed(curSpeed);
changeSpeedMillis = millis() + CHANGE_SPEED_TIME;
}
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}
Have you considered that your troubles are caused by interference from the currents flowing into your motors?
If your motors are DC brush, then more interference may be radiated from the brushes back into your various wires.
As a first step, perhaps let only one motor work and see if hangups diminish in frequency (although, to be sure, you need a 'scope onto a few wires carrying logic signals.

Display ADC result on LCD or Terminal using CodevisionAVR

My project is an audio spectrum analyzer, but I am stuck in displaying the ADC results, either on my LCD or on the Terminal of CodevisionAVR.
The project uses an ATmega16A, with an 7.37 MHz external oscillator. For an IDE I am using CodevisionAVR.
The audio spectrum analyzer takes its input through a 3.5 mm jack audio cable, this signal is amplified and filtered in order to select the frequencies between 0 and 4 KHz, and the output of this circuit is connected to PA0, which is the channel 0 of the ADC of the microcontroller.
For testing, I have set the ADC to work on 8 bits (read the most significant 8 bits), taking the internal 2.56V as voltage reference. I have decoupled AREF pin using a 10nF capacitor (I will change it to 100nF for a better noise reduction). The ADC is also in free running mode.
I am stuck in displaying the ADC results, either on my LCD or on the Terminal of CodevisionAVR (through the UART --- configured using the wizard).
This is the function I used for the ADC:
// Voltage Reference: Int., cap. on AREF
#define ADC_VREF_TYPE ((1<<REFS1) | (1<<REFS0) | (1<<ADLAR))
// Read the 8 most significant bits
// of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCH;
}
Main function of the code:
void main (void)
{
Init_Controller(); // this must be the first "init" action/call!
#asm("sei") // enable interrupts
lcd_init(16);
lcd_gotoxy(0,1);
lcd_putsf("AUDIO SPECTRUM");
delay_ms(3000);
lcd_clear();
while(TRUE)
{
wdogtrig();
TCNT1 = 0; //usage of Timer1 with OCR1A
TIFR |= 1<<OCF1A;
for(i=0;i<N;i++) {
while((TIFR & (1<<OCF1A)) == 0)
putchar(read_adc());
//adc_set[i] = adc_read(); //this is a second option
TIFR |= 1<<OCF1A;
}
//for(i=0; i<N; i++)
//printf("adc values: %d \n",adc_set[i]);
} //end while loop
}
N is defined as 32 = number of samples in 1 AD conversion.
The first error I see is using putchar() to write a number to the LCD.
The result of read_adc() is a number, not a string of ascii characters. You need to use sprintf to write the ADC result as a string into a buffer, then use lcd_putsf() to send the buffer to the LCD.

Resources