ATSAM3x8e and SPI - Page 1
Forum section: electronics / general

author: MyElectronsFellOut
author_rank: Regular Contributor
timestamp: July 05, 2016, 08:29:12 am
content: I'm struggling here a bit. I have setup the SPI bus on this chip to talk to a touchscreen digitizer (AD7873). The digitizer takes a control byte to initiate a conversion. No probs here. It then takes 2 x 8 clock bursts on the SPI bus to get the data out of the digitizer. Again no problem with doing this.What I am seeing on the scope is three bursts of 8 clock cycles - 1 burst for data in, 2 bursts for data out. The data out is as follows:0xAA 0x80 or 0xE1 0x00 etc... you get the idea.I have setup the Interrupt for the "Receive Data Full Register" so that when data arrives, the flag goes up and I can read it out of the register. The problem is that even though I can see data on the scope, for some reason the first byte goes missing. The data in register is 16-bits wide but it's unclear if this register is 'full' after one byte when operating in 8-bit mode, or full after both bytes arrive.I have tried various methods of reading the register to try and isolate the upper and lower parts of the data in register, two reads of the lower byte and so on, but all I can get out is the last byte received (usually 0x80 or 0x00).Some code.Code:PIOC->PIO_PER = PIO_PC19;// CS Pin-Manual Control, Active Low (could have tied this to a dedicated CS, muppet!)PIOC->PIO_OER = PIO_PC19;// OutputPIOC->PIO_SODR = PIO_PC19; // HighPIOC->PIO_PER = PIO_PC18;// Status PinPIOC->PIO_ODR = PIO_PC18;// InputPIOC->PIO_PUDR = PIO_PC18; // Disable Pull UpSerialPI.SPI_Setup(Mode0, 2, 8);// Mode 0, 2 MHz Clock, 8 Bits / Transfer----------------------------------- SPI Setup Function// Interrupts ------------SPI0->SPI_IER |= SPI_IER_RDRF;// Receive Data Full InterruptNVIC_EnableIRQ((IRQn_Type) ID_SPI0);// Add to the NVIC// Pin Setup ---------------PMC->PMC_PCER0 |= (1 << ID_PIOA);PIOA->PIO_ODR |= PIO_PA25;// MISO Pin - InputPIOA->PIO_PDR |= PIO_PA25;PIOA->PIO_ABSR &= ~(PIO_PA25);// MISO Pin - (A) PeripheralPIOA->PIO_OER |= PIO_PA26;// MOSI Pin - OutputPIOA->PIO_PDR |= PIO_PA26;PIOA->PIO_ABSR &= ~(PIO_PA26);// MOSI Pin - (A) PeripheralPIOA->PIO_OER |= PIO_PA27;// SCLK Pin - OutputPIOA->PIO_PDR |= PIO_PA27;PIOA->PIO_ABSR &= ~(PIO_PA27);// SCLK Pin - (A) PeripheralPIOA->PIO_OER |= PIO_PA28;// CS Pin 0 - OutputPIOA->PIO_PDR |= PIO_PA28;PIOA->PIO_ABSR &= ~(PIO_PA28);// CS Pin 0- (A) PeripheralPIOA->PIO_PUER |= PIO_PA28;// Disable the SPI to configure itSPI0->SPI_CR |= SPI_CR_SPIDIS;// SPI0 Setup --------------PMC->PMC_PCER0 = (1 << ID_SPI0);// Enable SPI0 Clock// Master Mode, Fixed Peripheral Mode, Mode fault detection disabled, Fixed peripheral modeSPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS;if(Mhz == 0) Mhz = 2;// Mhz CAN NOT equal 0, if user passes 0, set to default of 2// Mode and ClockClock Freq CalculationSPI0->SPI_CSR |= Mode | (((int8_t)(MasterClock / Mhz)) << 8);// Need to stick clock calculation in byte 2// 8 bits per transferif(BitsPerT == 8) SPI0->SPI_CSR |= SPI_CSR_BITS_8_BIT;// 9 bits per transferelse if(BitsPerT == 9) SPI0->SPI_CSR |= SPI_CSR_BITS_9_BIT;// 10 bits per transferelse if(BitsPerT == 10) SPI0->SPI_CSR |= SPI_CSR_BITS_10_BIT;// 11 bits per transferelse if(BitsPerT == 11) SPI0->SPI_CSR |= SPI_CSR_BITS_11_BIT;// 12 bits per transferelse if(BitsPerT == 12) SPI0->SPI_CSR |= SPI_CSR_BITS_12_BIT;// 13 bits per transferelse if(BitsPerT == 13) SPI0->SPI_CSR |= SPI_CSR_BITS_13_BIT;// 14 bits per transferelse if(BitsPerT == 14) SPI0->SPI_CSR |= SPI_CSR_BITS_14_BIT;// 15 bits per transferelse if(BitsPerT == 15) SPI0->SPI_CSR |= SPI_CSR_BITS_15_BIT;// 16 bits per transferelse if(BitsPerT == 16) SPI0->SPI_CSR |= SPI_CSR_BITS_16_BIT;// Default 8 bitselse SPI0->SPI_CSR |= SPI_CSR_BITS_8_BIT;SPI0->SPI_CR |= SPI_CR_SPIEN;// Enable SPI0--------------------------------- SPI Transmit Function// Store Data for referenceDataTx = Data;// Fill the Data Transfer Register (Should only fill the lower 2 bytes)SPI0->SPI_TDR |= DataTx;// Now clock out as many blank bytes as required until slave device has returned all the data required by the masterfor(uint8_t i = 0; i < NumBytes; i++) {while(!(SPI0->SPI_SR & SPI_SR_TXEMPTY));// Wait for TX Register to empty.SPI0->SPI_TDR |= 0x00;// Load up a blank byte}---------------------------------- Data Received Handler, have attempted many different methods of reading out the register (Simply the lower byte, lower byte and upper byte together, upper byte on first iteration, lower byte on second iteration etc..)if(SPI0->SPI_SR & SPI_SR_RDRF) {// Flag & register cleared when readif(SerialPI.ByteCount == 0){SerialPI.DataRx[SerialPI.ByteCount] = SPI0->SPI_RDR & 0xFF;SerialPI.ByteCount++;} else {SerialPI.DataRx[SerialPI.ByteCount] = SPI0->SPI_RDR & 0xFF;Serial1.Tx_Integer(SerialPI.DataRx);Serial1.Tx_String("-");Serial1.Tx_Integer(SerialPI.DataRx);Serial1.Tx_String("\r\n");SerialPI.ByteCount = 0;}}Will appreciate any help / advice on this sucker. Thanks.

author: MyElectronsFellOut
author_rank: Regular Contributor
timestamp: July 05, 2016, 12:42:09 pm
content: So some more info;With the AD7873 in 8 bit ADC mode, the two byte data format was thus... [-][bit 7][bit 6][bit 5][bit 4][bit 3][bit 2][bit 1] [bit 0][-][-][-][-][-][-][-] which explained why the lower byte was always 0 or 128.In 12 bit mode, I got two bytes of data as opposed to 0x00 0x80 / 0x00 0x00, but the data was (appeared) to be garbage compared with the decoded scope output.I removed the Data Received Full Register handler and have simply pulsed the SCLK line and waited for the data to arrive by checking the Status Flag register bit for Data Received. I then moved the data to an array and displayed the value (in hex) on the serial window. I now get matching data! But not quite there yet.Heres my code doing the SPI write and now readCode:// Fill the Data Transfer Register (Should only fill the lower 2 bytes)SPI0->SPI_TDR |= DataTx;// Now clock out as many blank bytes as required until slave device has returned all the data required by the masterfor(uint8_t i = 0; i < NumBytes; i++) {while(!(SPI0->SPI_SR & SPI_SR_TXEMPTY));// Wait for Register to empty.SPI0->SPI_TDR |= 0x00;// Load up a blank bytewhile(!(SPI0->SPI_SR & SPI_SR_RDRF));DataRx = SPI0->SPI_RDR & 0xFF;ByteCount++;}Serial1.Tx_Integer(DataRx);Serial1.Tx_String(" - ");Serial1.Tx_Integer(DataRx);Serial1.Tx_String("\r\n");ByteCount = 0;I should get the following; DataRx = Byte 1, DataRx = Byte 2What I actually get is DataRx = 0, DataRx = Byte 1Moving my finger across the screen verifies that the data is correct, it seems i'm just not processing this in the right manner. I can't work out why using the ISR handler lead to the data being absolute garbage, except for maybe not being able to print the data quick enough before it was overwritten by a new block of data?

author: MyElectronsFellOut
author_rank: Regular Contributor
timestamp: July 05, 2016, 01:29:49 pm
content: Ok.. resolved-ish.I have now retrieved both bytes in the correct order. Turns out I was trying to recover the data far too quickly. Still not sure why the interrupt handler was garbling the bytes up but I am now getting data out which is a step forward.This is my first foray into touchscreens and my first time using a 32-bit M3 cortex at 84Mhz, so still learning as I go.