Hi! I know this is not a forum dedicated to other boards featuring At91sam9g20, but I figured I could get some useful inputs from you.
Long story short, on SPI1 and CS 2 I have hooked a 12 bit ADC and this is the code that I use to initialize my peripheral. After debugging, I realized that it gets stuck when it reads the input buffer.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "at91sam9g20.h"
#define CS2_PIN AT91C_PC4_SPI1_NPCS2_0
void *pmc_base;
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
#define PMC_BASE 0xfffffc00
#define PMC_PCER 0x10
typedef unsigned char u08;
typedef signed char s08;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned long long u64;
typedef signed long long s64;
static int memMapFile;
static AT91PS_SYS at91_gpio_ctrl; /* bit 4 on port C is ADC's chip select, so PIO must be used */
static AT91PS_SPI at91spi_ctrl;
static AT91PS_PMC at91_pmc_ctrl;
/* *****************************************************************************
SOFTWARE API FOR PIO
***************************************************************************** */
//*----------------------------------------------------------------------------
//* \fn AT91F_PIO_CfgPeriph
//* \brief Enable pins to be drived by peripheral // found on ATMEL's forums
//*----------------------------------------------------------------------------
__inline void AT91F_PIO_CfgPeriph(
AT91PS_PIO pPio, // \arg pointer to a PIO controller
unsigned int periphAEnable, // \arg PERIPH A to enable
unsigned int periphBEnable) // \arg PERIPH B to enable
{
pPio->PIO_ASR = periphAEnable;
pPio->PIO_BSR = periphBEnable;
pPio->PIO_PDR = (periphAEnable | periphBEnable); // Set in Periph mode
}
u16 spiTransferWord(u16 TxData)
{
unsigned int RxData = 0;
//ENABLE 16 BIT TRANSFER
at91spi_ctrl->SPI_CSR[1] |= AT91C_SPI_BITS_16;
//MASK UNUSED BITS
TxData &= 0x0000FFFF;
//WAIT UNTIL TRANSMIT REGISTER IS EMPTY
while (!(at91spi_ctrl ->SPI_SR & AT91C_SPI_TXEMPTY));
// TRANSMIT DATA
at91spi_ctrl ->SPI_TDR = TxData;
//READ THE RECEIVED DATA
//WAIT UNTIL RECEIVE REGISTER IS FULL
while (!(at91spi_ctrl -> SPI_SR & AT91C_SPI_RDRF));
//READ RDR AND MASK UNUSED BITS
RxData = (at91spi_ctrl -> SPI_RDR & 0x0000FFFF);
return RxData;
}
void open_memory(){
if ((memMapFile = open("/dev/mem", O_RDWR | O_SYNC ))<0) {
printf("Couldn't open /dev/mem. Exiting ...\n");
}
at91_gpio_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned) AT91C_BASE_AIC ) ;
at91spi_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned)AT91C_BASE_SPI1);
at91_pmc_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned) AT91C_BASE_PMC & ~MAP_MASK);
pmc_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, PMC_BASE & ~MAP_MASK);
if ( (at91spi_ctrl== MAP_FAILED) && (at91_gpio_ctrl== MAP_FAILED) )
{
printf("ERROR: Unable to mmap the system controller\n");
close (memMapFile);
memMapFile = -1;
//return (errno);
}
}
void spi_setup(){
at91_pmc_ctrl -> PMC_SCER = AT91C_CKGR_MOSCEN;
*((volatile unsigned long *) (pmc_base + ((PMC_BASE + PMC_PCER) & MAP_MASK))) = (1< PIOB_ASR = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOB_PDR = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOB_PPUER = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOB_BSR = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOC_ASR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_PDR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_PPUER = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_BSR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_CODR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_PPUDR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_PER = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_OER = AT91C_PC4_SPI1_NPCS2_0;
at91spi_ctrl-> SPI_CR = AT91C_SPI_SPIDIS ;
at91spi_ctrl -> SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST ;
at91spi_ctrl -> SPI_CR = AT91C_SPI_SWRST ;
at91spi_ctrl -> SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PS_FIXED | (0x0)<<16;
at91spi_ctrl -> SPI_CSR[1] = AT91C_SPI_CPOL | AT91C_SPI_NCPHA | AT91C_SPI_BITS_16 | AT91C_SPI_CSAAT | ( 4 << 8);
printf("%d \n", at91spi_ctrl -> SPI_CSR[1]);
}
int main(void){
open_memory();
spi_setup();
//at91_gpio_ctrl -> PIOC_SODR = CS2_PIN;
while (1) {
// at91_gpio_ctrl -> PIOC_CODR = CS2_PIN; // no need for this, CS is toggled automatically.
//sleep(5);
printf("%d \n",spiTransferWord(0));
//at91_gpio_ctrl -> PIOC_SODR = CS2_PIN;
//sleep(5);
}
at91spi_ctrl -> SPI_CR = AT91C_SPI_SPIDIS ;
return 0;
}

Re: External ADC on SPI1
I don't know. Telling from your code you are using Linux, so my first question would be, why do you not use the Linux interface driver?
Just a short look on your code:
at91_gpio_ctrl -> PIOC_ASR = AT91C_PC4_SPI1_NPCS2_0;
Here you mux SPI1_NPCS2 as peripheral, which is correct.
A few lines off you do:
at91_gpio_ctrl -> PIOC_PER = AT91C_PC4_SPI1_NPCS2_0;
Yiu mux it back as GPIO, that can't work imho.
Re: External ADC on SPI1
Thank you for taking the time to look at my code. '
Indeed, I shouldn't have done the GPIO move. However, I still couldn't get anything out of it. Here's the cleaned-up listing:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "at91sam9g20.h"
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
typedef unsigned char u08;
typedef signed char s08;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned long long u64;
typedef signed long long s64;
static int memMapFile;
static AT91PS_SYS at91_gpio_ctrl;
static AT91PS_SPI at91spi_ctrl;
static AT91PS_PMC at91_pmc_ctrl;
u16 spiTransferWord(u16 TxData)
{
unsigned int RxData = 0;
//ENABLE 16 BIT TRANSFER
at91spi_ctrl->SPI_CSR[2] |= AT91C_SPI_BITS_16;
//MASK UNUSED BITS
TxData &= 0x0000FFFF;
//WAIT UNTIL TRANSMIT REGISTER IS EMPTY
while (!(at91spi_ctrl ->SPI_SR & AT91C_SPI_TXEMPTY));
// TRANSMIT DATA
at91spi_ctrl ->SPI_TDR = TxData;
//READ THE RECEIVED DATA
//WAIT UNTIL RECEIVE REGISTER IS FULL
while (!(at91spi_ctrl -> SPI_SR & AT91C_SPI_RDRF));
//READ RDR AND MASK UNUSED BITS
RxData = (at91spi_ctrl -> SPI_RDR & 0x0000FFFF);
return RxData;
}
void open_memory(){
if ((memMapFile = open("/dev/mem", O_RDWR | O_SYNC ))<0) {
printf("Couldn't open /dev/mem. Exiting ...\n");
}
at91_gpio_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned) AT91C_BASE_AIC ) ;
at91spi_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned) AT91C_BASE_SPI1);
at91_pmc_ctrl = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFile, (unsigned) AT91C_BASE_PMC & ~MAP_MASK);
if ( (at91spi_ctrl== MAP_FAILED) && (at91_gpio_ctrl== MAP_FAILED) )
{
printf("ERROR: Unable to mmap the system controller\n");
close (memMapFile);
memMapFile = -1;
//return (errno);AT91PS_PMC
}
}
void spi_setup(){
// PMC setting
at91_pmc_ctrl-> PMC_PCER = (1 lsh AT91C_ID_SPI1);
// peripherals definition(s)
at91_gpio_ctrl -> PIOB_ASR = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOC_ASR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOB_PDR = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOC_PDR = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOB_PPUER = AT91C_PB0_SPI1_MISO | AT91C_PB1_SPI1_MOSI | AT91C_PB2_SPI1_SPCK;
at91_gpio_ctrl -> PIOC_PPUER = AT91C_PC4_SPI1_NPCS2_0;
at91_gpio_ctrl -> PIOC_OER = AT91C_PC4_SPI1_NPCS2_0;
// SPI settings
at91spi_ctrl -> SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST ;
at91spi_ctrl -> SPI_CR = AT91C_SPI_SWRST ;
at91spi_ctrl -> SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PS_FIXED ;
at91spi_ctrl -> SPI_CSR[2] = AT91C_SPI_CPOL | AT91C_SPI_NCPHA | AT91C_SPI_BITS_16 | AT91C_SPI_CSAAT| 1<<8;
printf("%d \n", at91spi_ctrl -> SPI_CSR[2]);
}
int main(void){
open_memory();
spi_setup();
while (1) {
usleep(0);
printf("%d \n",spiTransferWord(0));
}
// it never gets here
at91spi_ctrl -> SPI_CR = AT91C_SPI_SPIDIS ;
return 0;
}
Re: External ADC on SPI1
Actually I have only used SPI by using DMA myself. I think the Enable and Softwarereset should be after you have written the control and configuration registers, also why do you still set the output of the Chipselect? After you have muxed it as peripheral, the AT91 Hardware IP will handle this port. In your transfer routine you set the controller again to 16 bit, although you have already done that in your initialization routine, this is just not necessary.
I would recommend to have a look at the Linux driver to model your code, or even best configure a common spi-device in Linux and you will have something like /dev/spi0 in your device tree to which you can read/write by common file i/o.
Re: External ADC on SPI1
I posted an update on my progress on atmel's forums. I was able to start the SPI interface, but the CS2 (or PC4) would not toggle.
Here's the link: http://www.at91.com/forum/viewtopic.php/f,9/t,19459/