Unfinished AT91SAM7 SPI driver.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2266 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2010-10-17 19:40:36 +00:00
parent bef0924474
commit b7e7258008
7 changed files with 202 additions and 68 deletions

View File

@ -91,13 +91,4 @@
#define PIOB_PHY_IRQ 26
#define PIOB_PHY_IRQ_MASK (1 << PIOB_PHY_IRQ)
#define MMC_CSR_NUM 1
/*
* SPI0 pins
*/
#define SPI_MISO (1 << 16)
#define SPI_MOSI (1 << 17)
#define SPI_SCK (1 << 18)
#endif /* _BOARD_H_ */

View File

@ -71,13 +71,4 @@
#define PIOA_MMC_NPCS0 11
#define PIOA_MMC_NPCS0_MASK (1 << PIOA_MMC_NPCS0_MASK)
#define MMC_CSR_NUM 0
/*
* SPI pins
*/
#define SPI_MISO (1 << 12)
#define SPI_MOSI (1 << 13)
#define SPI_SCK (1 << 14)
#endif /* _BOARD_H_ */

View File

@ -45,17 +45,17 @@ static bool_t fs_ready = FALSE;
/* Maximum speed SPI configuration (__MHz, NCPHA=1, CPOL=0).*/
static SPIConfig hs_spicfg = {
NULL,
IOPORT1,
PIOA_CS_MMC,
AT91C_SPI_MSTR | AT91C_SPI_MODFDIS,
(MAX_SPI_BITRATE << 8) | AT91C_SPI_NCPHA | AT91C_SPI_BITS_8
};
/* Low speed SPI configuration (192KHz, NCPHA=1, CPOL=0).*/
static SPIConfig ls_spicfg = {
NULL,
IOPORT1,
PIOA_CS_MMC,
AT91C_SPI_MSTR | AT91C_SPI_MODFDIS,
(MIN_SPI_BITRATE << 8) | AT91C_SPI_NCPHA | AT91C_SPI_BITS_8
};

View File

@ -248,8 +248,8 @@ CH_IRQ_HANDLER(USART1IrqHandler) {
}
#endif
// note - DBGU_UART IRQ is the SysIrq in board.c
// since it's not vectored separately by the AIC
/* note - DBGU_UART IRQ is the SysIrq in board.c
since it's not vectored separately by the AIC.*/
/*===========================================================================*/
/* Driver exported functions. */
@ -286,9 +286,9 @@ void sd_lld_init(void) {
#if USE_SAM7_DBGU_UART
sdObjectInit(&SD3, NULL, notify3);
// this is a little cheap, but OK for now since there's enough overlap
// between dbgu and usart register maps. it means we can reuse all the
// same usart interrupt handling and config that already exists
/* this is a little cheap, but OK for now since there's enough overlap
between dbgu and usart register maps. it means we can reuse all the
same usart interrupt handling and config that already exists.*/
SD3.usart = (AT91PS_USART)AT91C_BASE_DBGU;
AT91C_BASE_PIOA->PIO_PDR = SAM7_DBGU_RX | SAM7_DBGU_TX;
AT91C_BASE_PIOA->PIO_ASR = SAM7_DBGU_RX | SAM7_DBGU_TX;
@ -328,7 +328,8 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
AIC_EnableIT(AT91C_ID_US1);
}
#endif
// note - no explicit start for SD3 (DBGU_UART) since it's not included in the AIC or PMC
/* Note - no explicit start for SD3 (DBGU_UART) since it's not included
in the AIC or PMC.*/
}
usart_init(sdp, config);
}

View File

@ -34,9 +34,14 @@
/* Driver exported variables. */
/*===========================================================================*/
#if USE_AT91SAM7_SPI || defined(__DOXYGEN__)
/** @brief SPI driver identifier.*/
SPIDriver SPID;
#if AT91SAM7_SPI_USE_SPI0 || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
#if AT91SAM7_SPI_USE_SPI1 || defined(__DOXYGEN__)
/** @brief SPI2 driver identifier.*/
SPIDriver SPID2;
#endif
/*===========================================================================*/
@ -81,6 +86,36 @@ void rw8(size_t n, const uint8_t *txbuf, uint8_t *rxbuf) {
/* Driver interrupt handlers. */
/*===========================================================================*/
#if AT91SAM7_SPI_USE_SPI0 || defined(__DOXYGEN__)
/**
* @brief SPI0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPI0IrqHandler) {
CH_IRQ_PROLOGUE();
spi_lld_serve_interrupt(&SPID1);
AT91C_BASE_AIC->AIC_EOICR = 0;
CH_IRQ_EPILOGUE();
}
#endif
#if AT91SAM7_SPI_USE_SPI1 || defined(__DOXYGEN__)
/**
* @brief SPI1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SPI1IrqHandler) {
CH_IRQ_PROLOGUE();
spi_lld_serve_interrupt(&SPID2);
AT91C_BASE_AIC->AIC_EOICR = 0;
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@ -92,8 +127,32 @@ void rw8(size_t n, const uint8_t *txbuf, uint8_t *rxbuf) {
*/
void spi_lld_init(void) {
#if USE_AT91SAM7_SPI
spiObjectInit(&SPID);
#if AT91SAM7_SPI_USE_SPI0
spiObjectInit(&SPID1);
/* Software reset must be written twice (errata for revision B parts).*/
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_PIOA->PIO_PDR = SPI0_MISO | SPI0_MOSI | SPI0_SCK;
AT91C_BASE_PIOA->PIO_ASR = SPI0_MISO | SPI0_MOSI | SPI0_SCK;
AT91C_BASE_PIOA->PIO_PPUDR = SPI0_MISO | SPI0_MOSI | SPI0_SCK;
SPID1.spd_spi = AT91C_BASE_SPI0;
AIC_ConfigureIT(AT91C_ID_SPI0,
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_SPI0_PRIORITY,
SPI0IrqHandler);
#endif
#if AT91SAM7_SPI_USE_SPI1
spiObjectInit(&SPID2);
/* Software reset must be written twice (errata for revision B parts).*/
AT91C_BASE_SPI1->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI1->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_PIOA->PIO_PDR = SPI1_MISO | SPI1_MOSI | SPI1_SCK;
AT91C_BASE_PIOA->PIO_BSR = SPI1_MISO | SPI1_MOSI | SPI1_SCK;
AT91C_BASE_PIOA->PIO_PPUDR = SPI1_MISO | SPI1_MOSI | SPI1_SCK;
SPID2.spd_spi = AT91C_BASE_SPI1;
AIC_ConfigureIT(AT91C_ID_SPI1,
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_SPI1_PRIORITY,
SPI1IrqHandler);
#endif
}
@ -107,21 +166,29 @@ void spi_lld_init(void) {
void spi_lld_start(SPIDriver *spip) {
if (spip->spd_state == SPI_STOP) {
/* disable general-purpose I/O for SPI pins */
AT91C_BASE_PIOA->PIO_PDR = SPI_MISO | SPI_MOSI | SPI_SCK;
/* select perepheral A for SPI pins*/
AT91C_BASE_PIOA->PIO_ASR = SPI_MISO | SPI_MOSI | SPI_SCK;
/* Clock activation.*/
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
#if AT91SAM7_SPI_USE_SPI0
if (&SPID1 == spip) {
/* Clock activation.*/
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI0);
/* Enables associated interrupt vector.*/
AIC_EnableIT(AT91C_ID_SPI0);
}
#endif
#if AT91SAM7_SPI_USE_SPI1
if (&SPID2 == spip) {
/* Clock activation.*/
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI1);
/* Enables associated interrupt vector.*/
AIC_EnableIT(AT91C_ID_SPI1);
}
#endif
}
/* software reset must be written twice (errata for revision B parts) */
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
else
spip->spd_spi->SPI_CR = AT91C_SPI_SPIDIS;
/* Configuration.*/
AT91C_BASE_SPI->SPI_MR = spip->spd_config->spc_mr;
AT91C_BASE_SPI->SPI_CSR[MMC_CSR_NUM] = spip->spd_config->spc_csr;
/* Enable SPI */
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
spip->spd_spi->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS;
spip->spd_spi->SPI_CSR[0] = spip->spd_config->spc_csr;
spip->spd_spi->SPI_CR = AT91C_SPI_SPIEN;
}
/**
@ -134,10 +201,20 @@ void spi_lld_start(SPIDriver *spip) {
void spi_lld_stop(SPIDriver *spip) {
if (spip->spd_state != SPI_STOP) {
/* disable SPI */
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
/* disable clocks to SPI perepheral */
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_SPI);
#if AT91SAM7_SPI_USE_SPI0
if (&SPID1 == spip) {
spip->spd_spi->SPI_CR = AT91C_SPI_SPIDIS;
spip->spd_spi->PMC_PCDR = (1 << AT91C_ID_SPI0);
AIC_DisableIT(AT91C_ID_SPI0);
}
#endif
#if AT91SAM7_SPI_USE_SPI1
if (&SPID1 == spip) {
spip->spd_spi->SPI_CR = AT91C_SPI_SPIDIS;
spip->spd_spi->PMC_PCDR = (1 << AT91C_ID_SPI1);
AIC_DisableIT(AT91C_ID_SPI0);
}
#endif
}
}

View File

@ -31,11 +31,24 @@
#if CH_HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Device compatibility. SAM7X have 2 SPIs. */
/* Device compatibility.. */
/*===========================================================================*/
#if defined (AT91SAM7X256_H)
#define AT91C_BASE_SPI AT91C_BASE_SPI0
#define AT91C_ID_SPI AT91C_ID_SPI0
#if defined (AT91C_BASE_SPI)
#define AT91C_BASE_SPI0 AT91C_BASE_SPI
#define AT91C_ID_SPI0 AT91C_ID_SPI
#define SPI0_MISO (1 << 12)
#define SPI0_MOSI (1 << 13)
#define SPI0_SCK (1 << 14)
#else
#define SPI0_MISO (1 << 16)
#define SPI0_MOSI (1 << 17)
#define SPI0_SCK (1 << 18)
#define SPI1_MISO (1 << 24)
#define SPI1_MOSI (1 << 23)
#define SPI1_SCK (1 << 22)
#endif
/*===========================================================================*/
@ -47,26 +60,74 @@
/*===========================================================================*/
/**
* @brief SPI driver enable switch.
* @brief SPID1 enable switch (SPI0 device).
* @details If set to @p TRUE the support for SPI0 is included.
* @note The default is @p TRUE.
*/
#if !defined(USE_AT91SAM7_SPI) || defined(__DOXYGEN__)
#define USE_AT91SAM7_SPI TRUE
#if !defined(AT91SAM7_SPI_USE_SPI0) || defined(__DOXYGEN__)
#define AT91SAM7_SPI_USE_SPI0 TRUE
#endif
/**
* @brief SPID2 enable switch (SPI1 device).
* @details If set to @p TRUE the support for SPI1 is included.
* @note The default is @p TRUE.
*/
#if !defined(AT91SAM7_SPI_USE_SPI1) || defined(__DOXYGEN__)
#define AT91SAM7_SPI_USE_SPI1 TRUE
#endif
/**
* @brief SPI0 device interrupt priority level setting.
*/
#if !defined(AT91SAM7_SPI0_PRIORITY) || defined(__DOXYGEN__)
#define AT91SAM7_SPI0_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 1)
#endif
/**
* @brief SPI1 device interrupt priority level setting.
*/
#if !defined(AT91SAM7_SPI1_PRIORITY) || defined(__DOXYGEN__)
#define AT91SAM7_SPI1_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 1)
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !AT91SAM7_SPI_USE_SPI0 && !AT91SAM7_SPI_USE_SPI1
#error "SPI driver activated but no SPI peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
* @note In order to use synchronous functions this field must be set to
* @p NULL, callbacks and synchronous operations are mutually
* exclusive.
*/
spicallback_t spc_endcb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
@ -75,10 +136,6 @@ typedef struct {
* @brief The chip select line pad number.
*/
uint16_t spc_sspad;
/**
* @brief SPI Mode Register initialization data.
*/
uint32_t spc_mr;
/**
* @brief SPI Chip Select Register initialization data.
*/
@ -88,11 +145,21 @@ typedef struct {
/**
* @brief Structure representing a SPI driver.
*/
typedef struct {
struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t spd_state;
/**
* @brief Current configuration data.
*/
const SPIConfig *spd_config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *spd_thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
@ -103,12 +170,15 @@ typedef struct {
Semaphore spd_semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
/**
* @brief Current configuration data.
*/
const SPIConfig *spd_config;
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
} SPIDriver;
/**
* @brief Pointer to the SPIx registers block.
*/
AT91PS_SPI spd_spi;
};
/*===========================================================================*/
/* Driver macros. */
@ -118,8 +188,12 @@ typedef struct {
/* External declarations. */
/*===========================================================================*/
#if USE_AT91SAM7_SPI && !defined(__DOXYGEN__)
extern SPIDriver SPID;
#if AT91SAM7_SPI_USE_SPI0 && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
#if AT91SAM7_SPI_USE_SPI1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus

View File

@ -244,7 +244,7 @@ struct SPIDriver{
*/
stm32_dma_channel_t *spd_dmatx;
/**
* @brief DMA priority bit mask.\
* @brief DMA priority bit mask.
*/
uint32_t spd_dmaccr;
};