mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-12-07 06:12:12 +00:00
ChibiOS 2.6.8, until I can figure out where to get it from git.
This commit is contained in:
387
firmware/chibios/os/hal/platforms/AT91SAM7/adc_lld.c
Executable file
387
firmware/chibios/os/hal/platforms/AT91SAM7/adc_lld.c
Executable file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
This file has been contributed by:
|
||||
Andrew Hannam aka inmarket.
|
||||
*/
|
||||
/**
|
||||
* @file AT91SAM7/adc_lld.c
|
||||
* @brief AT91SAM7 ADC subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup ADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_ADC || defined(__DOXYGEN__)
|
||||
|
||||
/**
|
||||
* @brief ADC1 Prescaler
|
||||
* @detail Prescale = RoundUp(MCK / 2 / ADCClock - 1)
|
||||
*/
|
||||
#if ((((MCK/2)+(AT91_ADC1_CLOCK-1))/AT91_ADC1_CLOCK)-1) > 255
|
||||
#define AT91_ADC1_PRESCALE 255
|
||||
#else
|
||||
#define AT91_ADC1_PRESCALE ((((MCK/2)+(AT91_ADC1_CLOCK-1))/AT91_ADC1_CLOCK)-1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC1 Startup Time
|
||||
* @details Startup = RoundUp(ADCClock / 400,000 - 1)
|
||||
* @note Corresponds to a startup delay > 20uS (as required from the datasheet)
|
||||
*/
|
||||
#if (((AT91_ADC1_CLOCK+399999)/400000)-1) > 127
|
||||
#define AT91_ADC1_STARTUP 127
|
||||
#else
|
||||
#define AT91_ADC1_STARTUP (((AT91_ADC1_CLOCK+399999)/400000)-1)
|
||||
#endif
|
||||
|
||||
#if AT91_ADC1_RESOLUTION == 8
|
||||
#define AT91_ADC1_MAINMODE (((AT91_ADC1_SHTM & 0x0F) << 24) | ((AT91_ADC1_STARTUP & 0x7F) << 16) | ((AT91_ADC1_PRESCALE & 0xFF) << 8) | AT91C_ADC_LOWRES_8_BIT)
|
||||
#else
|
||||
#define AT91_ADC1_MAINMODE (((AT91_ADC1_SHTM & 0x0F) << 24) | ((AT91_ADC1_STARTUP & 0x7F) << 16) | ((AT91_ADC1_PRESCALE & 0xFF) << 8) | AT91C_ADC_LOWRES_10_BIT)
|
||||
#endif
|
||||
|
||||
#if AT91_ADC1_TIMER < 0 || AT91_ADC1_TIMER > 2
|
||||
#error "Unknown Timer specified for ADC1"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !ADC_USE_ADC1
|
||||
#error "You must specify ADC_USE_ADC1 if you have specified HAL_USE_ADC"
|
||||
#endif
|
||||
|
||||
/** @brief ADC1 driver identifier.*/
|
||||
ADCDriver ADCD1;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define ADCReg1 ((AT91S_ADC *)AT91C_ADC_CR)
|
||||
|
||||
#if AT91_ADC1_MAINMODE == 2
|
||||
#define ADCTimer1 ((AT91S_TC *)AT91C_TC2_CCR)
|
||||
#define AT91_ADC1_TIMERMODE AT91C_ADC_TRGSEL_TIOA2
|
||||
#define AT91_ADC1_TIMERID AT91C_ID_TC2
|
||||
#elif AT91_ADC1_MAINMODE == 1
|
||||
#define ADCTimer1 ((AT91S_TC *)AT91C_TC1_CCR)
|
||||
#define AT91_ADC1_TIMERMODE AT91C_ADC_TRGSEL_TIOA1
|
||||
#define AT91_ADC1_TIMERID AT91C_ID_TC1
|
||||
#else
|
||||
#define ADCTimer1 ((AT91S_TC *)AT91C_TC0_CCR)
|
||||
#define AT91_ADC1_TIMERMODE AT91C_ADC_TRGSEL_TIOA0
|
||||
#define AT91_ADC1_TIMERID AT91C_ID_TC0
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define adc_sleep() ADCReg1->ADC_MR = (AT91_ADC1_MAINMODE | AT91C_ADC_SLEEP_MODE | AT91C_ADC_TRGEN_DIS)
|
||||
#define adc_wake() ADCReg1->ADC_MR = (AT91_ADC1_MAINMODE | AT91C_ADC_SLEEP_NORMAL_MODE | AT91C_ADC_TRGEN_DIS)
|
||||
#define adc_disable() { \
|
||||
ADCReg1->ADC_IDR = 0xFFFFFFFF; \
|
||||
ADCReg1->ADC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; \
|
||||
adc_wake(); \
|
||||
ADCReg1->ADC_CHDR = 0xFF; \
|
||||
}
|
||||
#define adc_clrint() { \
|
||||
uint32_t isr, dummy; \
|
||||
\
|
||||
isr = ADCReg1->ADC_SR; \
|
||||
if ((isr & AT91C_ADC_DRDY)) dummy = ADCReg1->ADC_LCDR; \
|
||||
if ((isr & AT91C_ADC_EOC0)) dummy = ADCReg1->ADC_CDR0; \
|
||||
if ((isr & AT91C_ADC_EOC1)) dummy = ADCReg1->ADC_CDR1; \
|
||||
if ((isr & AT91C_ADC_EOC2)) dummy = ADCReg1->ADC_CDR2; \
|
||||
if ((isr & AT91C_ADC_EOC3)) dummy = ADCReg1->ADC_CDR3; \
|
||||
if ((isr & AT91C_ADC_EOC4)) dummy = ADCReg1->ADC_CDR4; \
|
||||
if ((isr & AT91C_ADC_EOC5)) dummy = ADCReg1->ADC_CDR5; \
|
||||
if ((isr & AT91C_ADC_EOC6)) dummy = ADCReg1->ADC_CDR6; \
|
||||
if ((isr & AT91C_ADC_EOC7)) dummy = ADCReg1->ADC_CDR7; \
|
||||
(void) dummy; \
|
||||
}
|
||||
#define adc_stop() { \
|
||||
adc_disable(); \
|
||||
adc_clrint(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* We must keep stack usage to a minimum - the default AT91SAM7 isr stack size is very small.
|
||||
* We sacrifice some speed and code size in order to achieve this by accessing the structure
|
||||
* and registers directly rather than through the passed in pointers. This works because the
|
||||
* AT91SAM7 supports only a single ADC device (although with 8 channels).
|
||||
*/
|
||||
static void handleint(void) {
|
||||
uint32_t isr;
|
||||
|
||||
isr = ADCReg1->ADC_SR;
|
||||
|
||||
if (ADCD1.grpp) {
|
||||
|
||||
/* ADC overflow condition, this could happen only if the DMA is unable to read data fast enough.*/
|
||||
if ((isr & AT91C_ADC_GOVRE)) {
|
||||
_adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW);
|
||||
|
||||
/* Transfer complete processing.*/
|
||||
} else if ((isr & AT91C_ADC_RXBUFF)) {
|
||||
if (ADCD1.grpp->circular) {
|
||||
/* setup the DMA again */
|
||||
ADCReg1->ADC_RPR = (uint32_t)ADCD1.samples;
|
||||
if (ADCD1.depth <= 1) {
|
||||
ADCReg1->ADC_RCR = ADCD1.grpp->num_channels;
|
||||
ADCReg1->ADC_RNPR = 0;
|
||||
ADCReg1->ADC_RNCR = 0;
|
||||
} else {
|
||||
ADCReg1->ADC_RCR = ADCD1.depth/2 * ADCD1.grpp->num_channels;
|
||||
ADCReg1->ADC_RNPR = (uint32_t)(ADCD1.samples + (ADCD1.depth/2 * ADCD1.grpp->num_channels));
|
||||
ADCReg1->ADC_RNCR = (ADCD1.depth - ADCD1.depth/2) * ADCD1.grpp->num_channels;
|
||||
}
|
||||
ADCReg1->ADC_PTCR = AT91C_PDC_RXTEN; // DMA enabled
|
||||
}
|
||||
_adc_isr_full_code(&ADCD1);
|
||||
|
||||
/* Half transfer processing.*/
|
||||
} else if ((isr & AT91C_ADC_ENDRX)) {
|
||||
// Make sure we get a full complete next time.
|
||||
ADCReg1->ADC_RNPR = 0;
|
||||
ADCReg1->ADC_RNCR = 0;
|
||||
_adc_isr_half_code(&ADCD1);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Spurious interrupt - Make sure it doesn't happen again */
|
||||
adc_disable();
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief ADC interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(ADC_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
handleint();
|
||||
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level ADC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_init(void) {
|
||||
/* Turn on ADC in the power management controller */
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_ADC);
|
||||
|
||||
/* Driver object initialization.*/
|
||||
adcObjectInit(&ADCD1);
|
||||
|
||||
ADCReg1->ADC_CR = 0; // 0 or AT91C_ADC_SWRST if you want to do a ADC reset
|
||||
adc_stop();
|
||||
adc_sleep();
|
||||
|
||||
/* Setup interrupt handler */
|
||||
AIC_ConfigureIT(AT91C_ID_ADC,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_ADC_IRQ_PRIORITY,
|
||||
ADC_IRQHandler);
|
||||
AIC_EnableIT(AT91C_ID_ADC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the ADC peripheral.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_start(ADCDriver *adcp) {
|
||||
|
||||
/* If in stopped state then wake up the ADC */
|
||||
if (adcp->state == ADC_STOP) {
|
||||
|
||||
/* Take it out of sleep mode */
|
||||
/* We could stay in sleep mode provided total conversion rate < 44kHz but we can't guarantee that here */
|
||||
adc_wake();
|
||||
|
||||
/* TODO: We really should perform a conversion here just to ensure that we are out of sleep mode */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the ADC peripheral.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_stop(ADCDriver *adcp) {
|
||||
if (adcp->state != ADC_READY) {
|
||||
adc_stop();
|
||||
adc_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts an ADC conversion.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_start_conversion(ADCDriver *adcp) {
|
||||
uint32_t i;
|
||||
(void) adcp;
|
||||
|
||||
/* Make sure everything is stopped first */
|
||||
adc_stop();
|
||||
|
||||
/* Safety check the trigger value */
|
||||
switch(ADCD1.grpp->trigger & ~ADC_TRIGGER_SOFTWARE) {
|
||||
case ADC_TRIGGER_TIMER:
|
||||
case ADC_TRIGGER_EXTERNAL:
|
||||
break;
|
||||
default:
|
||||
((ADCConversionGroup *)ADCD1.grpp)->trigger = ADC_TRIGGER_SOFTWARE;
|
||||
ADCD1.depth = 1;
|
||||
((ADCConversionGroup *)ADCD1.grpp)->circular = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Count the real number of activated channels in case the user got it wrong */
|
||||
((ADCConversionGroup *)ADCD1.grpp)->num_channels = 0;
|
||||
for(i=1; i < 0x100; i <<= 1) {
|
||||
if ((ADCD1.grpp->channelselects & i))
|
||||
((ADCConversionGroup *)ADCD1.grpp)->num_channels++;
|
||||
}
|
||||
|
||||
/* Set the channels */
|
||||
ADCReg1->ADC_CHER = ADCD1.grpp->channelselects;
|
||||
|
||||
/* Set up the DMA */
|
||||
ADCReg1->ADC_RPR = (uint32_t)ADCD1.samples;
|
||||
if (ADCD1.depth <= 1 || !ADCD1.grpp->circular) {
|
||||
ADCReg1->ADC_RCR = ADCD1.depth * ADCD1.grpp->num_channels;
|
||||
ADCReg1->ADC_RNPR = 0;
|
||||
ADCReg1->ADC_RNCR = 0;
|
||||
} else {
|
||||
ADCReg1->ADC_RCR = ADCD1.depth/2 * ADCD1.grpp->num_channels;
|
||||
ADCReg1->ADC_RNPR = (uint32_t)(ADCD1.samples + (ADCD1.depth/2 * ADCD1.grpp->num_channels));
|
||||
ADCReg1->ADC_RNCR = (ADCD1.depth - ADCD1.depth/2) * ADCD1.grpp->num_channels;
|
||||
}
|
||||
ADCReg1->ADC_PTCR = AT91C_PDC_RXTEN;
|
||||
|
||||
/* Set up interrupts */
|
||||
ADCReg1->ADC_IER = AT91C_ADC_GOVRE | AT91C_ADC_ENDRX | AT91C_ADC_RXBUFF;
|
||||
|
||||
/* Set the trigger */
|
||||
switch(ADCD1.grpp->trigger & ~ADC_TRIGGER_SOFTWARE) {
|
||||
case ADC_TRIGGER_TIMER:
|
||||
// Set up the timer if ADCD1.grpp->frequency != 0
|
||||
if (ADCD1.grpp->frequency) {
|
||||
/* Turn on Timer in the power management controller */
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91_ADC1_TIMERID);
|
||||
|
||||
/* Disable the clock and the interrupts */
|
||||
ADCTimer1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
ADCTimer1->TC_IDR = 0xFFFFFFFF;
|
||||
|
||||
/* Set the Mode of the Timer Counter and calculate the period */
|
||||
i = (MCK/2)/ADCD1.grpp->frequency;
|
||||
if (i < (0x10000<<0)) {
|
||||
ADCTimer1->TC_CMR = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | AT91C_TC_LDRA_RISING |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CLKS_TIMER_DIV1_CLOCK);
|
||||
} else if (i < (0x10000<<2)) {
|
||||
i >>= 2;
|
||||
ADCTimer1->TC_CMR = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | AT91C_TC_LDRA_RISING |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CLKS_TIMER_DIV2_CLOCK);
|
||||
} else if (i < (0x10000<<4)) {
|
||||
i >>= 4;
|
||||
ADCTimer1->TC_CMR = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | AT91C_TC_LDRA_RISING |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CLKS_TIMER_DIV3_CLOCK);
|
||||
} else if (i < (0x10000<<6)) {
|
||||
i >>= 6;
|
||||
ADCTimer1->TC_CMR = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | AT91C_TC_LDRA_RISING |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CLKS_TIMER_DIV4_CLOCK);
|
||||
} else {
|
||||
i >>= 9;
|
||||
ADCTimer1->TC_CMR = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | AT91C_TC_LDRA_RISING |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CLKS_TIMER_DIV5_CLOCK);
|
||||
}
|
||||
|
||||
/* RC is the period, RC-RA is the pulse width (in this case = 1) */
|
||||
ADCTimer1->TC_RC = i;
|
||||
ADCTimer1->TC_RA = i - 1;
|
||||
|
||||
/* Start the timer counter */
|
||||
ADCTimer1->TC_CCR = (AT91C_TC_CLKEN |AT91C_TC_SWTRG);
|
||||
}
|
||||
|
||||
ADCReg1->ADC_MR = AT91_ADC1_MAINMODE | AT91C_ADC_SLEEP_NORMAL_MODE | AT91C_ADC_TRGEN_EN | AT91_ADC1_TIMERMODE;
|
||||
break;
|
||||
|
||||
case ADC_TRIGGER_EXTERNAL:
|
||||
/* Make sure the ADTRG pin is set as an input - assume pull-ups etc have already been set */
|
||||
#if (SAM7_PLATFORM == SAM7S64) || (SAM7_PLATFORM == SAM7S128) || (SAM7_PLATFORM == SAM7S256) || (SAM7_PLATFORM == SAM7S512)
|
||||
AT91C_BASE_PIOA->PIO_ODR = AT91C_PA8_ADTRG;
|
||||
#elif (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || (SAM7_PLATFORM == SAM7X512)
|
||||
AT91C_BASE_PIOB->PIO_ODR = AT91C_PB18_ADTRG;
|
||||
#endif
|
||||
ADCReg1->ADC_MR = AT91_ADC1_MAINMODE | AT91C_ADC_SLEEP_NORMAL_MODE | AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_EXT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ADCReg1->ADC_MR = AT91_ADC1_MAINMODE | AT91C_ADC_SLEEP_NORMAL_MODE | AT91C_ADC_TRGEN_DIS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Manually start a conversion if we need to */
|
||||
if (ADCD1.grpp->trigger & ADC_TRIGGER_SOFTWARE)
|
||||
ADCReg1->ADC_CR = AT91C_ADC_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops an ongoing conversion.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_stop_conversion(ADCDriver *adcp) {
|
||||
(void) adcp;
|
||||
adc_stop();
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_ADC */
|
||||
|
||||
/** @} */
|
||||
303
firmware/chibios/os/hal/platforms/AT91SAM7/adc_lld.h
Executable file
303
firmware/chibios/os/hal/platforms/AT91SAM7/adc_lld.h
Executable file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
This file has been contributed by:
|
||||
Andrew Hannam aka inmarket.
|
||||
*/
|
||||
/**
|
||||
* @file AT91SAM7/adc_lld.h
|
||||
* @brief AT91SAM7 ADC subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup ADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _ADC_LLD_H_
|
||||
#define _ADC_LLD_H_
|
||||
|
||||
#if HAL_USE_ADC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Trigger Sources
|
||||
* @{
|
||||
*/
|
||||
#define ADC_TRIGGER_SOFTWARE 0x8000 /**< @brief Software Triggering - Can be combined with another value */
|
||||
#define ADC_TRIGGER_TIMER 0x0001 /**< @brief TIO Timer Counter Channel */
|
||||
#define ADC_TRIGGER_EXTERNAL 0x0002 /**< @brief External Trigger */
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief ADC1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(ADC_USE_ADC1) || defined(__DOXYGEN__)
|
||||
#define ADC_USE_ADC1 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC1 Timer to use when a periodic conversion is requested.
|
||||
* @details Should be set to 0..2
|
||||
* @note The default is 0
|
||||
*/
|
||||
#if !defined(AT91_ADC1_TIMER) || defined(__DOXYGEN__)
|
||||
#define AT91_ADC1_TIMER 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC1 Resolution.
|
||||
* @details Either 8 or 10 bits
|
||||
* @note The default is 10 bits.
|
||||
*/
|
||||
#if !defined(AT91_ADC1_RESOLUTION) || defined(__DOXYGEN__)
|
||||
#define AT91_ADC1_RESOLUTION 10
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC1 Clock
|
||||
* @details Maximum is 5MHz for 10bit or 8MHz for 8bit
|
||||
* @note The default is calculated from AT91_ADC1_RESOLUTION to give the fastest possible ADCClock
|
||||
*/
|
||||
#if !defined(AT91_ADC1_CLOCK) || defined(__DOXYGEN__)
|
||||
#if AT91_ADC1_RESOLUTION == 8
|
||||
#define AT91_ADC1_CLOCK 8000000
|
||||
#else
|
||||
#define AT91_ADC1_CLOCK 5000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC1 Sample and Hold Time
|
||||
* @details SHTM = RoundUp(ADCClock * SampleHoldTime). Range = RoundUp(ADCClock / 1,666,666) to 15
|
||||
* @note Default corresponds to the minimum sample and hold time (600nS from the datasheet)
|
||||
* @note Increasing the Sample Hold Time increases the ADC input impedance
|
||||
*/
|
||||
#if !defined(AT91_ADC1_SHTM) || defined(__DOXYGEN__)
|
||||
#define AT91_ADC1_SHTM 0
|
||||
#endif
|
||||
#if AT91_ADC1_SHTM < ((AT91_ADC1_CLOCK+1666665)/1666666)
|
||||
#undef AT91_ADC1_SHTM
|
||||
#define AT91_ADC1_SHTM ((AT91_ADC1_CLOCK+1666665)/1666666)
|
||||
#endif
|
||||
#if AT91_ADC1_SHTM > 15
|
||||
#undef AT91_ADC1_SHTM
|
||||
#define AT91_ADC1_SHTM 15
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(AT91_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define AT91_ADC_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(AT91_DMA_REQUIRED)
|
||||
#define AT91_DMA_REQUIRED
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief ADC sample data type.
|
||||
*/
|
||||
#if AT91_ADC1_RESOLUTION == AT91C_ADC_LOWRES_8_BIT
|
||||
typedef uint8_t adcsample_t;
|
||||
#else
|
||||
typedef uint16_t adcsample_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Channels number in a conversion group.
|
||||
*/
|
||||
typedef uint16_t adc_channels_num_t;
|
||||
|
||||
/**
|
||||
* @brief Possible ADC failure causes.
|
||||
* @note Error codes are architecture dependent and should not relied
|
||||
* upon.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_ERR_OVERFLOW = 0, /**< ADC overflow condition. Something is not working fast enough. */
|
||||
} adcerror_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an ADC driver.
|
||||
*/
|
||||
typedef struct ADCDriver ADCDriver;
|
||||
|
||||
/**
|
||||
* @brief ADC notification callback type.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object triggering the
|
||||
* callback
|
||||
* @param[in] buffer pointer to the most recent samples data
|
||||
* @param[in] n number of buffer rows available starting from @p buffer
|
||||
*/
|
||||
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
|
||||
|
||||
/**
|
||||
* @brief ADC error callback type.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object triggering the
|
||||
* callback
|
||||
* @param[in] err ADC error code
|
||||
*/
|
||||
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
|
||||
|
||||
/**
|
||||
* @brief Conversion group configuration structure.
|
||||
* @details This implementation-dependent structure describes a conversion
|
||||
* operation.
|
||||
* @note The use of this configuration structure requires knowledge of
|
||||
* STM32 ADC cell registers interface, please refer to the STM32
|
||||
* reference manual for details.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Enables the circular buffer mode for the group.
|
||||
*/
|
||||
bool_t circular;
|
||||
/**
|
||||
* @brief Number of the analog channels belonging to the conversion group.
|
||||
*/
|
||||
adc_channels_num_t num_channels;
|
||||
/**
|
||||
* @brief Callback function associated to the group or @p NULL.
|
||||
*/
|
||||
adccallback_t end_cb;
|
||||
/**
|
||||
* @brief Error callback or @p NULL.
|
||||
*/
|
||||
adcerrorcallback_t error_cb;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Select the ADC Channels to read.
|
||||
* @details The number of bits at logic level one in this register must
|
||||
* be equal to the number in the @p num_channels field.
|
||||
*/
|
||||
uint16_t channelselects;
|
||||
/**
|
||||
* @brief Select how to trigger the conversion.
|
||||
*/
|
||||
uint16_t trigger;
|
||||
/**
|
||||
* @brief When in ADC_TRIGGER_TIMER trigger mode - what frequency?
|
||||
*/
|
||||
uint32_t frequency;
|
||||
} ADCConversionGroup;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
} ADCConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an ADC driver.
|
||||
*/
|
||||
struct ADCDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
adcstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const ADCConfig *config;
|
||||
/**
|
||||
* @brief Current samples buffer pointer or @p NULL.
|
||||
*/
|
||||
adcsample_t *samples;
|
||||
/**
|
||||
* @brief Current samples buffer depth or @p 0.
|
||||
*/
|
||||
size_t depth;
|
||||
/**
|
||||
* @brief Current conversion group pointer or @p NULL.
|
||||
*/
|
||||
const ADCConversionGroup *grpp;
|
||||
#if ADC_USE_WAIT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Waiting thread.
|
||||
*/
|
||||
Thread *thread;
|
||||
#endif
|
||||
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the peripheral.
|
||||
*/
|
||||
Mutex mutex;
|
||||
#elif CH_USE_SEMAPHORES
|
||||
Semaphore semaphore;
|
||||
#endif
|
||||
#endif /* ADC_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(ADC_DRIVER_EXT_FIELDS)
|
||||
ADC_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if ADC_USE_ADC1 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void adc_lld_init(void);
|
||||
void adc_lld_start(ADCDriver *adcp);
|
||||
void adc_lld_stop(ADCDriver *adcp);
|
||||
void adc_lld_start_conversion(ADCDriver *adcp);
|
||||
void adc_lld_stop_conversion(ADCDriver *adcp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_ADC */
|
||||
|
||||
#endif /* _ADC_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
3352
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7A3.h
Executable file
3352
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7A3.h
Executable file
File diff suppressed because it is too large
Load Diff
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S128.h
Executable file
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S128.h
Executable file
File diff suppressed because it is too large
Load Diff
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S256.h
Executable file
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S256.h
Executable file
File diff suppressed because it is too large
Load Diff
2303
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S512.h
Executable file
2303
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S512.h
Executable file
File diff suppressed because it is too large
Load Diff
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S64.h
Executable file
2229
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7S64.h
Executable file
File diff suppressed because it is too large
Load Diff
2914
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X128.h
Executable file
2914
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X128.h
Executable file
File diff suppressed because it is too large
Load Diff
2918
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X256.h
Executable file
2918
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X256.h
Executable file
File diff suppressed because it is too large
Load Diff
2984
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X512.h
Executable file
2984
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/AT91SAM7X512.h
Executable file
File diff suppressed because it is too large
Load Diff
84
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/aic.c
Executable file
84
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/aic.c
Executable file
@@ -0,0 +1,84 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support - ROUSSET -
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2006, Atmel Corporation
|
||||
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaiimer below.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the disclaimer below in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "aic.h"
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the interrupt associated with the given source, using the
|
||||
/// specified mode and interrupt handler.
|
||||
/// \param source Interrupt source to configure.
|
||||
/// \param mode Triggering mode of the interrupt.
|
||||
/// \param handler Interrupt handler function.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_ConfigureIT(unsigned int source,
|
||||
unsigned int mode,
|
||||
void (*handler)( void ))
|
||||
{
|
||||
// Disable the interrupt first
|
||||
AT91C_BASE_AIC->AIC_IDCR = 1 << source;
|
||||
|
||||
// Configure mode and handler
|
||||
AT91C_BASE_AIC->AIC_SMR[source] = mode;
|
||||
AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) handler;
|
||||
|
||||
// Clear interrupt
|
||||
AT91C_BASE_AIC->AIC_ICCR = 1 << source;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables interrupts coming from the given (unique) source.
|
||||
/// \param source Interrupt source to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_EnableIT(unsigned int source)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_IECR = 1 << source;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables interrupts coming from the given (unique) source.
|
||||
/// \param source Interrupt source to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_DisableIT(unsigned int source)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_IDCR = 1 << source;
|
||||
}
|
||||
|
||||
78
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/aic.h
Executable file
78
firmware/chibios/os/hal/platforms/AT91SAM7/at91lib/aic.h
Executable file
@@ -0,0 +1,78 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support - ROUSSET -
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2006, Atmel Corporation
|
||||
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaiimer below.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the disclaimer below in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Methods and definitions for configuring interrupts using the Advanced
|
||||
/// Interrupt Controller (AIC).
|
||||
///
|
||||
/// !Usage
|
||||
/// -# Configure an interrupt source using AIC_ConfigureIT
|
||||
/// -# Enable or disable interrupt generation of a particular source with
|
||||
/// AIC_EnableIT and AIC_DisableIT.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef AIC_H
|
||||
#define AIC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
|
||||
/// Redefinition of missing constant.
|
||||
#define AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void AIC_ConfigureIT(unsigned int source,
|
||||
unsigned int mode,
|
||||
void (*handler)( void ));
|
||||
|
||||
extern void AIC_EnableIT(unsigned int source);
|
||||
|
||||
extern void AIC_DisableIT(unsigned int source);
|
||||
|
||||
#endif //#ifndef AIC_H
|
||||
|
||||
56
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7.h
Executable file
56
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7.h
Executable file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AT91SAM7_H_
|
||||
#define _AT91SAM7_H_
|
||||
|
||||
/*
|
||||
* Supported platforms.
|
||||
*/
|
||||
#define SAM7S64 0
|
||||
#define SAM7S128 1
|
||||
#define SAM7S256 2
|
||||
#define SAM7S512 3
|
||||
#define SAM7X128 4
|
||||
#define SAM7X256 5
|
||||
#define SAM7X512 6
|
||||
#define SAM7A3 7
|
||||
|
||||
#ifndef SAM7_PLATFORM
|
||||
#error "SAM7 platform not defined"
|
||||
#endif
|
||||
|
||||
#if SAM7_PLATFORM == SAM7S64
|
||||
#include "at91lib/AT91SAM7S64.h"
|
||||
#elif SAM7_PLATFORM == SAM7S128
|
||||
#include "at91lib/AT91SAM7S128.h"
|
||||
#elif SAM7_PLATFORM == SAM7S256
|
||||
#include "at91lib/AT91SAM7S256.h"
|
||||
#elif SAM7_PLATFORM == SAM7S512
|
||||
#include "at91lib/AT91SAM7S512.h"
|
||||
#elif SAM7_PLATFORM == SAM7X128
|
||||
#include "at91lib/AT91SAM7X128.h"
|
||||
#elif SAM7_PLATFORM == SAM7X256
|
||||
#include "at91lib/AT91SAM7X256.h"
|
||||
#elif SAM7_PLATFORM == SAM7X512
|
||||
#include "at91lib/AT91SAM7X512.h"
|
||||
#elif SAM7_PLATFORM == SAM7A3
|
||||
#include "at91lib/AT91SAM7A3.h"
|
||||
#else
|
||||
#error "SAM7 platform not supported"
|
||||
#endif
|
||||
|
||||
#endif /* _AT91SAM7_H_ */
|
||||
144
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7_mii.c
Executable file
144
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7_mii.c
Executable file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/at91sam7_mii.c
|
||||
* @brief AT91SAM7 low level MII driver code.
|
||||
*
|
||||
* @addtogroup AT91SAM7_MII
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "at91sam7_mii.h"
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level MII driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void miiInit(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a PHY device.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void miiReset(MACDriver *macp) {
|
||||
|
||||
(void)macp;
|
||||
|
||||
/*
|
||||
* Disables the pullups on all the pins that are latched on reset by the PHY.
|
||||
*/
|
||||
AT91C_BASE_PIOB->PIO_PPUDR = PHY_LATCHED_PINS;
|
||||
|
||||
#ifdef PIOB_PHY_PD_MASK
|
||||
/*
|
||||
* PHY power control.
|
||||
*/
|
||||
AT91C_BASE_PIOB->PIO_OER = PIOB_PHY_PD_MASK; /* Becomes an output. */
|
||||
AT91C_BASE_PIOB->PIO_PPUDR = PIOB_PHY_PD_MASK;/* Default pullup disabled. */
|
||||
#if (PHY_HARDWARE == PHY_DAVICOM_9161)
|
||||
AT91C_BASE_PIOB->PIO_CODR = PIOB_PHY_PD_MASK; /* Output to low level. */
|
||||
#else
|
||||
AT91C_BASE_PIOB->PIO_SODR = PIOB_PHY_PD_MASK; /* Output to high level. */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PHY reset by pulsing the NRST pin.
|
||||
*/
|
||||
AT91C_BASE_RSTC->RSTC_RMR = 0xA5000100;
|
||||
AT91C_BASE_RSTC->RSTC_RCR = 0xA5000000 | AT91C_RSTC_EXTRST;
|
||||
while (!(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a PHY register through the MII interface.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[in] addr the register address
|
||||
* @return The register value.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
phyreg_t miiGet(MACDriver *macp, phyaddr_t addr) {
|
||||
|
||||
(void)macp;
|
||||
AT91C_BASE_EMAC->EMAC_MAN = (0b01 << 30) | /* SOF */
|
||||
(0b10 << 28) | /* RW */
|
||||
(PHY_ADDRESS << 23) | /* PHYA */
|
||||
(addr << 18) | /* REGA */
|
||||
(0b10 << 16); /* CODE */
|
||||
while (!( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE))
|
||||
;
|
||||
return (phyreg_t)(AT91C_BASE_EMAC->EMAC_MAN & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a PHY register through the MII interface.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[in] addr the register address
|
||||
* @param[in] value the new register value
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void miiPut(MACDriver *macp, phyaddr_t addr, phyreg_t value) {
|
||||
|
||||
(void)macp;
|
||||
AT91C_BASE_EMAC->EMAC_MAN = (0b01 << 30) | /* SOF */
|
||||
(0b01 << 28) | /* RW */
|
||||
(PHY_ADDRESS << 23) | /* PHYA */
|
||||
(addr << 18) | /* REGA */
|
||||
(0b10 << 16) | /* CODE */
|
||||
value;
|
||||
while (!( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE))
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
/** @} */
|
||||
111
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7_mii.h
Executable file
111
firmware/chibios/os/hal/platforms/AT91SAM7/at91sam7_mii.h
Executable file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/at91sam7_mii.h
|
||||
* @brief AT91SAM7 low level MII driver header.
|
||||
*
|
||||
* @addtogroup AT91SAM7_MII
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _AT91SAM7_MII_H_
|
||||
#define _AT91SAM7_MII_H_
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define PHY_MICREL_KS8721 0
|
||||
#define PHY_DAVICOM_9161 1
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief PHY manufacturer and model.
|
||||
*/
|
||||
#if !defined(PHY_HARDWARE) || defined(__DOXYGEN__)
|
||||
#define PHY_HARDWARE PHY_MICREL_KS8721
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Pins latched by the PHY at reset.
|
||||
*/
|
||||
#if PHY_HARDWARE == PHY_MICREL_KS8721
|
||||
#define PHY_ADDRESS 1
|
||||
#define PHY_ID MII_KS8721_ID
|
||||
#define PHY_LATCHED_PINS (AT91C_PB4_ECRS | AT91C_PB5_ERX0 | \
|
||||
AT91C_PB6_ERX1 | AT91C_PB7_ERXER | \
|
||||
AT91C_PB13_ERX2 | AT91C_PB14_ERX3 | \
|
||||
AT91C_PB15_ERXDV_ECRSDV | AT91C_PB16_ECOL | \
|
||||
AT91C_PIO_PB26)
|
||||
|
||||
#elif PHY_HARDWARE == PHY_DAVICOM_9161
|
||||
#define PHY_ADDRESS 0
|
||||
#define PHY_ID MII_DM9161_ID
|
||||
#define PHY_LATCHED_PINS (AT91C_PB0_ETXCK_EREFCK | AT91C_PB4_ECRS | \
|
||||
AT91C_PB5_ERX0 | AT91C_PB6_ERX1 | \
|
||||
AT91C_PB7_ERXER | AT91C_PB13_ERX2 | \
|
||||
AT91C_PB14_ERX3 | AT91C_PB15_ERXDV_ECRSDV | \
|
||||
AT91C_PB16_ECOL | AT91C_PB17_ERXCK)
|
||||
#endif /* PHY_HARDWARE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a PHY register value.
|
||||
*/
|
||||
typedef uint16_t phyreg_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a PHY register address.
|
||||
*/
|
||||
typedef uint8_t phyaddr_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void miiInit(void);
|
||||
void miiReset(MACDriver *macp);
|
||||
phyreg_t miiGet(MACDriver *macp, phyaddr_t addr);
|
||||
void miiPut(MACDriver *macp, phyaddr_t addr, phyreg_t value);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
#endif /* _AT91SAM7_MII_H_ */
|
||||
|
||||
/** @} */
|
||||
235
firmware/chibios/os/hal/platforms/AT91SAM7/ext_lld.c
Executable file
235
firmware/chibios/os/hal/platforms/AT91SAM7/ext_lld.c
Executable file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/ext_lld.c
|
||||
* @brief AT91SAM7 EXT subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup EXT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_EXT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EXTDA driver identifier.
|
||||
*/
|
||||
EXTDriver EXTDA;
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
/**
|
||||
* @brief EXTDB driver identifier.
|
||||
*/
|
||||
EXTDriver EXTDB;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Handles external interrupts.
|
||||
*
|
||||
* @param[in] extp pointer to the driver that received the interrupt
|
||||
*/
|
||||
static void ext_lld_serveInterrupt(EXTDriver *extp) {
|
||||
uint32_t irqFlags;
|
||||
uint32_t ch;
|
||||
|
||||
chSysLockFromIsr();
|
||||
|
||||
/* Read flags of pending PIO interrupts.*/
|
||||
irqFlags = extp->pio->PIO_ISR;
|
||||
|
||||
/* Call callback function for any pending interrupt.*/
|
||||
for(ch = 0; ch < EXT_MAX_CHANNELS; ch++) {
|
||||
|
||||
/* Check if the channel is activated and if its IRQ flag is set.*/
|
||||
if((extp->config->channels[ch].mode &
|
||||
EXT_CH_MODE_ENABLED & EXT_CH_MODE_EDGES_MASK)
|
||||
&& ((1 << ch) & irqFlags)) {
|
||||
(extp->config->channels[ch].cb)(extp, ch);
|
||||
}
|
||||
}
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EXTI[0] interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(EXTIA_IRQHandler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
ext_lld_serveInterrupt(&EXTDA);
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
/**
|
||||
* @brief EXTI[1] interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(EXTIB_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
ext_lld_serveInterrupt(&EXTDB);
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level EXT driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void ext_lld_init(void) {
|
||||
|
||||
/* Driver initialization.*/
|
||||
extObjectInit(&EXTDA);
|
||||
|
||||
/* Set PIO base addresses.*/
|
||||
EXTDA.pio = AT91C_BASE_PIOA;
|
||||
|
||||
/* Set peripheral IDs.*/
|
||||
EXTDA.pid = AT91C_ID_PIOA;
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
/* Same for PIOB.*/
|
||||
extObjectInit(&EXTDB);
|
||||
EXTDB.pio = AT91C_BASE_PIOB;
|
||||
EXTDB.pid = AT91C_ID_PIOB;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the EXT peripheral.
|
||||
*
|
||||
* @param[in] extp pointer to the @p EXTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void ext_lld_start(EXTDriver *extp) {
|
||||
uint16_t ch;
|
||||
uint32_t ier = 0;
|
||||
const EXTConfig *config = extp->config;
|
||||
|
||||
switch(extp->pid) {
|
||||
case AT91C_ID_PIOA:
|
||||
AIC_ConfigureIT(AT91C_ID_PIOA, SAM7_computeSMR(config->mode,
|
||||
config->priority),
|
||||
EXTIA_IRQHandler);
|
||||
break;
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
case AT91C_ID_PIOB:
|
||||
AIC_ConfigureIT(AT91C_ID_PIOB, SAM7_computeSMR(config->mode,
|
||||
config->priority),
|
||||
EXTIB_IRQHandler);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable and Disable channels with respect to config.*/
|
||||
for(ch = 0; ch < EXT_MAX_CHANNELS; ch++) {
|
||||
ier |= (config->channels[ch].mode & EXT_CH_MODE_EDGES_MASK & EXT_CH_MODE_ENABLED ? 1 : 0) << ch;
|
||||
}
|
||||
extp->pio->PIO_IER = ier;
|
||||
extp->pio->PIO_IDR = ~ier;
|
||||
|
||||
/* Enable interrupt on corresponding PIO port in AIC.*/
|
||||
AIC_EnableIT(extp->pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the EXT peripheral.
|
||||
*
|
||||
* @param[in] extp pointer to the @p EXTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void ext_lld_stop(EXTDriver *extp) {
|
||||
|
||||
/* Disable interrupt on corresponding PIO port in AIC.*/
|
||||
AIC_DisableIT(extp->pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables an EXT channel.
|
||||
*
|
||||
* @param[in] extp pointer to the @p EXTDriver object
|
||||
* @param[in] channel channel to be enabled
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) {
|
||||
|
||||
chDbgCheck((extp->config->channels[channel].cb != NULL),
|
||||
"Call back pointer can not be NULL");
|
||||
|
||||
extp->pio->PIO_IER = (1 << channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables an EXT channel.
|
||||
*
|
||||
* @param[in] extp pointer to the @p EXTDriver object
|
||||
* @param[in] channel channel to be disabled
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) {
|
||||
|
||||
extp->pio->PIO_IDR = (1 << channel);
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_EXT */
|
||||
|
||||
/** @} */
|
||||
239
firmware/chibios/os/hal/platforms/AT91SAM7/ext_lld.h
Executable file
239
firmware/chibios/os/hal/platforms/AT91SAM7/ext_lld.h
Executable file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/ext_lld.h
|
||||
* @brief AT91SAM7 EXT subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup EXT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _EXT_LLD_H_
|
||||
#define _EXT_LLD_H_
|
||||
|
||||
#if HAL_USE_EXT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Pointer to the SAM7 AIC register block.
|
||||
*/
|
||||
#define SAM7_EXT_AIC ((AT91PS_AIC *)AT91C_BASE_AIC)
|
||||
|
||||
/**
|
||||
* @brief Number of channels within one ext driver.
|
||||
*/
|
||||
#define EXT_MAX_CHANNELS 32
|
||||
|
||||
/**
|
||||
* @brief Mask of priority bits in interrupt mode register.
|
||||
*/
|
||||
#define SAM7_EXT_PRIORITY_MASK 0x00000007
|
||||
|
||||
/**
|
||||
* @brief Shifter for priority bits in interrupt mode register.
|
||||
*/
|
||||
#define SAM7_EXT_PRIORITY_SHIFTER 0
|
||||
|
||||
/**
|
||||
* @brief Shifter for mode bits in interrupt mode register.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_SHIFTER 5
|
||||
|
||||
/*
|
||||
* On the SAM7 architecture, a single channel can only be enables or disabled
|
||||
* Hence, undefine the other channel mode constants
|
||||
*/
|
||||
#ifdef EXT_CH_MODE_RISING_EDGE
|
||||
#undef EXT_CH_MODE_RISING_EDGE
|
||||
#endif
|
||||
|
||||
#ifdef EXT_CH_MODE_FALLING_EDGE
|
||||
#undef EXT_CH_MODE_FALLING_EDGE
|
||||
#endif
|
||||
|
||||
#ifdef EXT_CH_MODE_BOTH_EDGES
|
||||
#undef EXT_CH_MODE_BOTH_EDGES
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name EXT channels mode
|
||||
* @{
|
||||
*/
|
||||
#define EXT_CH_MODE_ENABLED 1 /**< @brief Channel is enabled. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EXT drivers mode
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Mask for modes.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_MASK AT91C_AIC_SRCTYPE
|
||||
/**
|
||||
* @brief Falling edge callback.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_FALLING_EDGE AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE
|
||||
/**
|
||||
* @brief Rising edge callback.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_RISING_EDGE AT91C_AIC_SRCTYPE_POSITIVE_EDGE
|
||||
/**
|
||||
* @brief High-level callback.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_HIGH_LEVEL AT91C_AIC_SRCTYPE_HIGH_LEVEL
|
||||
/**
|
||||
* @brief Low-level callback.
|
||||
*/
|
||||
#define SAM7_EXT_MODE_LOW_LEVEL AT91C_AIC_SRCTYPE_EXT_LOW_LEVEL
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EXT drivers priorities
|
||||
* @{
|
||||
*/
|
||||
#define SAM7_EXT_PRIOR_HIGHEST AT91C_AIC_PRIOR_HIGHEST
|
||||
#define SAM7_EXT_PRIOR_LOWEST AT91C_AIC_PRIOR_LOWEST
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EXT channel identifier.
|
||||
*/
|
||||
typedef uint32_t expchannel_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an EXT generic notification callback.
|
||||
*
|
||||
* @param[in] extp pointer to the @p EXPDriver object triggering the
|
||||
* callback
|
||||
*/
|
||||
typedef void (*extcallback_t)(EXTDriver *extp, expchannel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Channel configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channel mode.
|
||||
*/
|
||||
uint32_t mode;
|
||||
/**
|
||||
* @brief Channel callback.
|
||||
*/
|
||||
extcallback_t cb;
|
||||
} EXTChannelConfig;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channel configurations.
|
||||
*/
|
||||
EXTChannelConfig channels[EXT_MAX_CHANNELS];
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief interrupt mode.
|
||||
*/
|
||||
uint32_t mode;
|
||||
/**
|
||||
* @brief interrupt priority.
|
||||
*/
|
||||
uint32_t priority;
|
||||
} EXTConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an EXT driver.
|
||||
*/
|
||||
struct EXTDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
extstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const EXTConfig *config;
|
||||
/* End of the mandatory fields.*/
|
||||
|
||||
/**
|
||||
* @brief Pointer to the corresponding PIO registers block.
|
||||
*/
|
||||
AT91PS_PIO pio;
|
||||
/**
|
||||
* @brief peripheral ID of the corresponding PIO block.
|
||||
*/
|
||||
uint32_t pid;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Computes the content for the interrupt source mode register.
|
||||
*/
|
||||
#define SAM7_computeSMR(mode, prio) ( \
|
||||
((mode & SAM7_EXT_MODE_MASK) << SAM7_EXT_MODE_SHIFTER) | \
|
||||
((prio & SAM7_EXT_PRIORITY_MASK) << SAM7_EXT_PRIORITY_SHIFTER) \
|
||||
)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern EXTDriver EXTDA;
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
extern EXTDriver EXTDB;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void ext_lld_init(void);
|
||||
void ext_lld_start(EXTDriver *extp);
|
||||
void ext_lld_stop(EXTDriver *extp);
|
||||
void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel);
|
||||
void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_EXT */
|
||||
|
||||
#endif /* _EXT_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
451
firmware/chibios/os/hal/platforms/AT91SAM7/gpt_lld.c
Executable file
451
firmware/chibios/os/hal/platforms/AT91SAM7/gpt_lld.c
Executable file
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/gpt_lld.c
|
||||
* @brief AT91SAM7 GPT subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup GPT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_GPT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief GPTD1 driver identifier.
|
||||
* @note The driver GPTD1 allocates the complex timer TC0 when enabled.
|
||||
*/
|
||||
#if AT91_GPT_USE_TC0 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 driver identifier.
|
||||
* @note The driver GPTD2 allocates the timer TC1 when enabled.
|
||||
*/
|
||||
#if AT91_GPT_USE_TC1 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD2;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 driver identifier.
|
||||
* @note The driver GPTD3 allocates the timer TC2 when enabled.
|
||||
*/
|
||||
#if AT91_GPT_USE_TC2 || defined(__DOXYGEN__)
|
||||
GPTDriver GPTD3;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Shared IRQ handler.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
*/
|
||||
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
|
||||
// Read the status to clear the interrupts
|
||||
{ uint32_t isr = gptp->tc->TC_SR; (void) isr; }
|
||||
|
||||
// Do the callback
|
||||
gptp->config->callback(gptp);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if AT91_GPT_USE_TC0
|
||||
/**
|
||||
* @brief TC1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(TC0_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
gpt_lld_serve_interrupt(&GPTD1);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* AT91_GPT_USE_TC0 */
|
||||
|
||||
#if AT91_GPT_USE_TC1
|
||||
/**
|
||||
* @brief TC1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(TC1_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
gpt_lld_serve_interrupt(&GPTD2);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* AT91_GPT_USE_TC1 */
|
||||
|
||||
#if AT91_GPT_USE_TC2
|
||||
/**
|
||||
* @brief TC1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(TC2_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
gpt_lld_serve_interrupt(&GPTD2);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
}
|
||||
#endif /* AT91_GPT_USE_TC2 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level GPT driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_init(void) {
|
||||
|
||||
#if AT91_GPT_USE_TC0
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); // Turn on the power
|
||||
GPTD1.tc = AT91C_BASE_TC0;
|
||||
gptObjectInit(&GPTD1);
|
||||
gpt_lld_stop(&GPTD1); // Make sure it is disabled
|
||||
AIC_ConfigureIT(AT91C_ID_TC0, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC0_IRQ_PRIORITY, TC0_IRQHandler);
|
||||
AIC_EnableIT(AT91C_ID_TC0);
|
||||
#endif
|
||||
|
||||
#if AT91_GPT_USE_TC1
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); // Turn on the power
|
||||
GPTD2.tc = AT91C_BASE_TC1;
|
||||
gptObjectInit(&GPTD2);
|
||||
gpt_lld_stop(&GPTD2); // Make sure it is disabled
|
||||
AIC_ConfigureIT(AT91C_ID_TC1, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC1_IRQ_PRIORITY, TC1_IRQHandler);
|
||||
AIC_EnableIT(AT91C_ID_TC1);
|
||||
#endif
|
||||
|
||||
#if AT91_GPT_USE_TC2
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC2); // Turn on the power
|
||||
GPTD3.tc = AT91C_BASE_TC2;
|
||||
gptObjectInit(&GPTD3);
|
||||
gpt_lld_stop(&GPTD3); // Make sure it is disabled
|
||||
AIC_ConfigureIT(AT91C_ID_TC2, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC2_IRQ_PRIORITY, TC2_IRQHandler);
|
||||
AIC_EnableIT(AT91C_ID_TC2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the GPT peripheral.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_start(GPTDriver *gptp) {
|
||||
uint32_t cmr, bmr;
|
||||
|
||||
bmr = *AT91C_TCB_BMR;
|
||||
cmr = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET |
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO);
|
||||
|
||||
// Calculate clock
|
||||
switch(gptp->config->clocksource) {
|
||||
case GPT_CLOCK_MCLK:
|
||||
switch(gptp->config->frequency) {
|
||||
case MCK/2: cmr |= AT91C_TC_CLKS_TIMER_DIV1_CLOCK; break;
|
||||
case MCK/8: cmr |= AT91C_TC_CLKS_TIMER_DIV2_CLOCK; break;
|
||||
case MCK/32: cmr |= AT91C_TC_CLKS_TIMER_DIV3_CLOCK; break;
|
||||
case MCK/128: cmr |= AT91C_TC_CLKS_TIMER_DIV4_CLOCK; break;
|
||||
case MCK/1024: cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; break;
|
||||
default:
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #1", "invalid frequency");
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GPT_CLOCK_FREQUENCY:
|
||||
/* The mode and period will be calculated when the timer is started */
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
case GPT_CLOCK_RE_TCLK0:
|
||||
case GPT_CLOCK_FE_TCLK0:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
cmr |= AT91C_TC_CLKS_XC0;
|
||||
#if AT91_GPT_USE_TC0
|
||||
if (gptp == &GPTD1) bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TCLK0;
|
||||
#endif
|
||||
break;
|
||||
case GPT_CLOCK_RE_TCLK1:
|
||||
case GPT_CLOCK_FE_TCLK1:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
cmr |= AT91C_TC_CLKS_XC1;
|
||||
#if AT91_GPT_USE_TC1
|
||||
if (gptp == &GPTD2) bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TCLK1;
|
||||
#endif
|
||||
break;
|
||||
case GPT_CLOCK_RE_TCLK2:
|
||||
case GPT_CLOCK_FE_TCLK2:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
cmr |= AT91C_TC_CLKS_XC2;
|
||||
#if AT91_GPT_USE_TC2
|
||||
if (gptp == &GPTD3) bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TCLK2;
|
||||
#endif
|
||||
break;
|
||||
case GPT_CLOCK_RE_TC0:
|
||||
case GPT_CLOCK_FE_TC0:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
#if AT91_GPT_USE_TC0
|
||||
if (gptp == &GPTD1) {
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #2", "invalid clock");
|
||||
cmr |= AT91C_TC_CLKS_XC0;
|
||||
bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_NONE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC1
|
||||
if (gptp == &GPTD2) {
|
||||
cmr |= AT91C_TC_CLKS_XC1;
|
||||
bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TIOA0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC2
|
||||
if (gptp == &GPTD3) {
|
||||
cmr |= AT91C_TC_CLKS_XC2;
|
||||
bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TIOA0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #3", "invalid GPT device");
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
case GPT_CLOCK_RE_TC1:
|
||||
case GPT_CLOCK_FE_TC1:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
#if AT91_GPT_USE_TC0
|
||||
if (gptp == &GPTD1) {
|
||||
cmr |= AT91C_TC_CLKS_XC0;
|
||||
bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TIOA1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC1
|
||||
if (gptp == &GPTD2) {
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #4", "invalid clock");
|
||||
cmr |= AT91C_TC_CLKS_XC1;
|
||||
bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_NONE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC2
|
||||
if (gptp == &GPTD3) {
|
||||
cmr |= AT91C_TC_CLKS_XC2;
|
||||
bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TIOA1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #5", "invalid GPT device");
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
case GPT_CLOCK_RE_TC2:
|
||||
case GPT_CLOCK_FE_TC2:
|
||||
if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI;
|
||||
#if AT91_GPT_USE_TC0
|
||||
if (gptp == &GPTD1) {
|
||||
cmr |= AT91C_TC_CLKS_XC0;
|
||||
bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TIOA2;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC1
|
||||
if (gptp == &GPTD2) {
|
||||
cmr |= AT91C_TC_CLKS_XC1;
|
||||
bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TIOA2;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if AT91_GPT_USE_TC2
|
||||
if (gptp == &GPTD3) {
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #6", "invalid clock");
|
||||
cmr |= AT91C_TC_CLKS_XC2;
|
||||
bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_NONE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #7", "invalid GPT device");
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
default:
|
||||
chDbgAssert(TRUE, "gpt_lld_start(), #8", "invalid clock");
|
||||
cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate clock gating
|
||||
chDbgAssert(gptp->config->clockgate == GPT_GATE_NONE || gptp->config->clockgate == GPT_GATE_TCLK0
|
||||
|| gptp->config->clockgate == GPT_GATE_TCLK1 || gptp->config->clockgate == GPT_GATE_TCLK2
|
||||
, "gpt_lld_start(), #9", "invalid clockgate");
|
||||
cmr |= ((uint32_t)(gptp->config->clockgate & 0x03)) << 4; // special magic numbers here
|
||||
|
||||
// Calculate triggers
|
||||
chDbgAssert(gptp->config->trigger == GPT_TRIGGER_NONE
|
||||
|| gptp->config->trigger == GPT_TRIGGER_RE_TIOB || gptp->config->trigger == GPT_TRIGGER_FE_TIOB || gptp->config->trigger == GPT_TRIGGER_BE_TIOB
|
||||
|| gptp->config->trigger == GPT_TRIGGER_RE_TCLK0 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK0 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK0
|
||||
|| gptp->config->trigger == GPT_TRIGGER_RE_TCLK1 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK1 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK1
|
||||
|| gptp->config->trigger == GPT_TRIGGER_RE_TCLK2 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK2 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK2
|
||||
, "gpt_lld_start(), #10", "invalid trigger");
|
||||
cmr |= ((uint32_t)(gptp->config->trigger & 0x03)) << 10; // special magic numbers here
|
||||
cmr |= ((uint32_t)(gptp->config->trigger & 0x30)) << (8-4); // special magic numbers here
|
||||
|
||||
/* Set everything up but disabled */
|
||||
gptp->tc->TC_CCR = AT91C_TC_CLKDIS;
|
||||
gptp->tc->TC_IDR = 0xFFFFFFFF;
|
||||
gptp->tc->TC_CMR = cmr;
|
||||
gptp->tc->TC_RC = 65535;
|
||||
gptp->tc->TC_RA = 32768;
|
||||
*AT91C_TCB_BMR = bmr;
|
||||
cmr = gptp->tc->TC_SR; // Clear any pending interrupts
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the GPT peripheral.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_stop(GPTDriver *gptp) {
|
||||
gptp->tc->TC_CCR = AT91C_TC_CLKDIS;
|
||||
gptp->tc->TC_IDR = 0xFFFFFFFF;
|
||||
{ uint32_t isr = gptp->tc->TC_SR; (void)isr; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the timer in continuous mode.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
* @param[in] interval period in ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
|
||||
gpt_lld_change_interval(gptp, interval);
|
||||
if (gptp->state == GPT_ONESHOT)
|
||||
gptp->tc->TC_CMR |= AT91C_TC_CPCDIS;
|
||||
else
|
||||
gptp->tc->TC_CMR &= ~AT91C_TC_CPCDIS;
|
||||
gptp->tc->TC_CCR = AT91C_TC_CLKEN|AT91C_TC_SWTRG;
|
||||
if (gptp->config->callback)
|
||||
gptp->tc->TC_IER = AT91C_TC_CPCS|AT91C_TC_COVFS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the timer.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_stop_timer(GPTDriver *gptp) {
|
||||
gptp->tc->TC_CCR = AT91C_TC_CLKDIS;
|
||||
gptp->tc->TC_IDR = 0xFFFFFFFF;
|
||||
{ uint32_t isr = gptp->tc->TC_SR; (void)isr; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the interval of GPT peripheral.
|
||||
* @details This function changes the interval of a running GPT unit.
|
||||
* @pre The GPT unit must have been activated using @p gptStart().
|
||||
* @pre The GPT unit must have been running in continuous mode using
|
||||
* @p gptStartContinuous().
|
||||
* @post The GPT unit interval is changed to the new value.
|
||||
* @note The function has effect at the next cycle start.
|
||||
*
|
||||
* @param[in] gptp pointer to a @p GPTDriver object
|
||||
* @param[in] interval new cycle time in timer ticks
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_change_interval(GPTDriver *gptp, gptcnt_t interval) {
|
||||
if (gptp->config->clocksource == GPT_CLOCK_FREQUENCY) {
|
||||
uint32_t rc, cmr;
|
||||
|
||||
// Reset the timer to the (possibly) new frequency value
|
||||
rc = (MCK/2)/gptp->config->frequency;
|
||||
if (rc < (0x10000<<0)) {
|
||||
cmr = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
||||
} else if (rc < (0x10000<<2)) {
|
||||
rc >>= 2;
|
||||
cmr = AT91C_TC_CLKS_TIMER_DIV2_CLOCK;
|
||||
} else if (rc < (0x10000<<4)) {
|
||||
rc >>= 4;
|
||||
cmr = AT91C_TC_CLKS_TIMER_DIV3_CLOCK;
|
||||
} else if (rc < (0x10000<<6)) {
|
||||
rc >>= 6;
|
||||
cmr = AT91C_TC_CLKS_TIMER_DIV4_CLOCK;
|
||||
} else {
|
||||
rc >>= 9;
|
||||
cmr = AT91C_TC_CLKS_TIMER_DIV5_CLOCK;
|
||||
}
|
||||
gptp->tc->TC_CMR = (gptp->tc->TC_CMR & ~AT91C_TC_CLKS) | cmr;
|
||||
gptp->tc->TC_RC = rc;
|
||||
gptp->tc->TC_RA = rc/2;
|
||||
} else {
|
||||
gptp->tc->TC_RC = interval;
|
||||
gptp->tc->TC_RA = interval/2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the timer in one shot mode and waits for completion.
|
||||
* @details This function specifically polls the timer waiting for completion
|
||||
* in order to not have extra delays caused by interrupt servicing,
|
||||
* this function is only recommended for short delays.
|
||||
*
|
||||
* @param[in] gptp pointer to the @p GPTDriver object
|
||||
* @param[in] interval time interval in ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
|
||||
|
||||
gpt_lld_change_interval(gptp, interval);
|
||||
gptp->tc->TC_CMR |= AT91C_TC_CPCDIS;
|
||||
gptp->tc->TC_CCR = AT91C_TC_CLKEN|AT91C_TC_SWTRG;
|
||||
while (!(gptp->tc->TC_SR & (AT91C_TC_CPCS|AT91C_TC_COVFS)));
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_GPT */
|
||||
|
||||
/** @} */
|
||||
230
firmware/chibios/os/hal/platforms/AT91SAM7/gpt_lld.h
Executable file
230
firmware/chibios/os/hal/platforms/AT91SAM7/gpt_lld.h
Executable file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/gpt_lld.h
|
||||
* @brief AT91SAM7 GPT subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup GPT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _GPT_LLD_H_
|
||||
#define _GPT_LLD_H_
|
||||
|
||||
#if HAL_USE_GPT || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief GPTD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(AT91_GPT_USE_TC0) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_USE_TC0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD2 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(AT91_GPT_USE_TC1) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_USE_TC1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for GPTD3 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(AT91_GPT_USE_TC2) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_USE_TC3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(AT91_GPT_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_TC0_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(AT91_GPT_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_TC1_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief GPTD3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(AT91_GPT_TC2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define AT91_GPT_TC2_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !AT91_GPT_USE_TC0 && !AT91_GPT_USE_TC1 && !AT91_GPT_USE_TC2
|
||||
#error "GPT driver activated but no TC peripheral assigned"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief GPT frequency type.
|
||||
*/
|
||||
typedef uint32_t gptfreq_t;
|
||||
|
||||
/**
|
||||
* @brief GPT counter type.
|
||||
*/
|
||||
typedef uint16_t gptcnt_t;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Timer clock in Hz.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* frequency specifications.
|
||||
*/
|
||||
gptfreq_t frequency;
|
||||
/**
|
||||
* @brief Timer callback pointer.
|
||||
* @note This callback is invoked on GPT counter events.
|
||||
*/
|
||||
gptcallback_t callback;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Timer Clock Source.
|
||||
*/
|
||||
uint8_t clocksource;
|
||||
#define GPT_CLOCK_MCLK 0 // @< Internal clock. frequency must = MCLK/2, MCLK/8, MCLK/32, MCLK/128 or MCLK/1024
|
||||
#define GPT_CLOCK_FREQUENCY 1 // @< Internal clock. interval is ignored. frequency determines rate
|
||||
#define GPT_CLOCK_RE_TCLK0 2 // @< External TCLK0. Rising Edge
|
||||
#define GPT_CLOCK_FE_TCLK0 3 // @< External TCLK0. Falling Edge
|
||||
#define GPT_CLOCK_RE_TCLK1 4 // @< External TCLK1. Rising Edge
|
||||
#define GPT_CLOCK_FE_TCLK1 5 // @< External TCLK1. Falling Edge
|
||||
#define GPT_CLOCK_RE_TCLK2 6 // @< External TCLK2. Rising Edge
|
||||
#define GPT_CLOCK_FE_TCLK2 7 // @< External TCLK2. Falling Edge
|
||||
#define GPT_CLOCK_RE_TC0 8 // @< TC0 output. Rising Edge. Do not use on TC0
|
||||
#define GPT_CLOCK_FE_TC0 9 // @< TC0 output. Falling Edge. Do not use on TC0
|
||||
#define GPT_CLOCK_RE_TC1 10 // @< TC1 output. Rising Edge. Do not use on TC1
|
||||
#define GPT_CLOCK_FE_TC1 11 // @< TC1 output. Falling Edge. Do not use on TC1
|
||||
#define GPT_CLOCK_RE_TC2 12 // @< TC2 output. Rising Edge. Do not use on TC2
|
||||
#define GPT_CLOCK_FE_TC2 13 // @< TC2 output. Falling Edge. Do not use on TC2
|
||||
uint8_t clockgate;
|
||||
#define GPT_GATE_NONE 0 // @< Clock gating off
|
||||
#define GPT_GATE_TCLK0 1 // @< Clock on TCLK0 active high signal. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_GATE_TCLK1 2 // @< Clock on TCLK1 active high signal. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_GATE_TCLK2 3 // @< Clock on TCLK2 active high signal. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
uint8_t trigger;
|
||||
#define GPT_TRIGGER_NONE 0x00 // @< Start immediately
|
||||
#define GPT_TRIGGER_RE_TIOB 0x10 // @< Start on TIOB signal. Rising Edge.
|
||||
#define GPT_TRIGGER_FE_TIOB 0x20 // @< Start on TIOB signal. Falling Edge.
|
||||
#define GPT_TRIGGER_BE_TIOB 0x30 // @< Start on TIOB signal. Both Edges.
|
||||
#define GPT_TRIGGER_RE_TCLK0 0x11 // @< Start on TCLK0 signal. Rising Edge. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_FE_TCLK0 0x21 // @< Start on TCLK0 signal. Falling Edge. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_BE_TCLK0 0x31 // @< Start on TCLK0 signal. Both Edges. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_RE_TCLK1 0x12 // @< Start on TCLK1 signal. Rising Edge. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_FE_TCLK1 0x22 // @< Start on TCLK1 signal. Falling Edge. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_BE_TCLK1 0x32 // @< Start on TCLK1 signal. Both Edges. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_RE_TCLK2 0x13 // @< Start on TCLK2 signal. Rising Edge. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_FE_TCLK2 0x23 // @< Start on TCLK2 signal. Falling Edge. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
#define GPT_TRIGGER_BE_TCLK2 0x33 // @< Start on TCLK2 signal. Both Edges. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead.
|
||||
} GPTConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a GPT driver.
|
||||
*/
|
||||
struct GPTDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
gptstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const GPTConfig *config;
|
||||
#if defined(GPT_DRIVER_EXT_FIELDS)
|
||||
GPT_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the TCx registers block.
|
||||
*/
|
||||
AT91S_TC *tc;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if AT91_GPT_USE_TC0 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD1;
|
||||
#endif
|
||||
|
||||
#if AT91_GPT_USE_TC1 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD2;
|
||||
#endif
|
||||
|
||||
#if AT91_GPT_USE_TC2 && !defined(__DOXYGEN__)
|
||||
extern GPTDriver GPTD3;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void gpt_lld_init(void);
|
||||
void gpt_lld_start(GPTDriver *gptp);
|
||||
void gpt_lld_stop(GPTDriver *gptp);
|
||||
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
|
||||
void gpt_lld_stop_timer(GPTDriver *gptp);
|
||||
void gpt_lld_change_interval(GPTDriver *gptp, gptcnt_t interval);
|
||||
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_GPT */
|
||||
|
||||
#endif /* _GPT_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
129
firmware/chibios/os/hal/platforms/AT91SAM7/hal_lld.c
Executable file
129
firmware/chibios/os/hal/platforms/AT91SAM7/hal_lld.c
Executable file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/hal_lld.c
|
||||
* @brief AT91SAM7 HAL subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup HAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static CH_IRQ_HANDLER(spurious_handler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
AT91SAM7_SPURIOUS_HANDLER_HOOK();
|
||||
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level HAL driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void hal_lld_init(void) {
|
||||
unsigned i;
|
||||
|
||||
/* FIQ Handler weak symbol defined in vectors.s.*/
|
||||
void FiqHandler(void);
|
||||
|
||||
/* Default AIC setup, the device drivers will modify it as needed.*/
|
||||
AT91C_BASE_AIC->AIC_ICCR = 0xFFFFFFFF;
|
||||
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (AT91_REG)FiqHandler;
|
||||
for (i = 1; i < 31; i++) {
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (AT91_REG)NULL;
|
||||
AT91C_BASE_AIC->AIC_EOICR = (AT91_REG)i;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (AT91_REG)spurious_handler;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AT91SAM7 clocks and PLL initialization.
|
||||
* @note All the involved constants come from the file @p board.h.
|
||||
* @note This function must be invoked only after the system reset.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void at91sam7_clock_init(void) {
|
||||
|
||||
/* wait for reset */
|
||||
while((AT91C_BASE_RSTC->RSTC_RSR & (AT91C_RSTC_SRCMP | AT91C_RSTC_NRSTL)) != AT91C_RSTC_NRSTL)
|
||||
;
|
||||
/* enable reset */
|
||||
AT91C_BASE_RSTC->RSTC_RMR = ((0xA5 << 24) | AT91C_RSTC_URSTEN);
|
||||
|
||||
/* Flash Memory: 1 wait state, about 50 cycles in a microsecond.*/
|
||||
#if SAM7_PLATFORM == SAM7X512
|
||||
AT91C_BASE_MC->MC0_FMR = (AT91C_MC_FMCN & (50 << 16)) | AT91C_MC_FWS_1FWS;
|
||||
AT91C_BASE_MC->MC1_FMR = (AT91C_MC_FMCN & (50 << 16)) | AT91C_MC_FWS_1FWS;
|
||||
#else
|
||||
AT91C_BASE_MC->MC_FMR = (AT91C_MC_FMCN & (50 << 16)) | AT91C_MC_FWS_1FWS;
|
||||
#endif
|
||||
|
||||
/* Enables the main oscillator and waits 56 slow cycles as startup time.*/
|
||||
AT91C_BASE_PMC->PMC_MOR = (AT91C_CKGR_OSCOUNT & (7 << 8)) | AT91C_CKGR_MOSCEN;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS))
|
||||
;
|
||||
|
||||
/* PLL setup: DIV = 14, MUL = 72, PLLCOUNT = 10
|
||||
PLLfreq = 96109714 Hz (rounded).*/
|
||||
AT91C_BASE_PMC->PMC_PLLR = (AT91C_CKGR_DIV & 14) |
|
||||
(AT91C_CKGR_PLLCOUNT & (10 << 8)) |
|
||||
(AT91SAM7_USBDIV) |
|
||||
(AT91C_CKGR_MUL & (72 << 16));
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK))
|
||||
;
|
||||
|
||||
/* Master clock = PLLfreq / 2 = 48054858 Hz (rounded).*/
|
||||
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY))
|
||||
;
|
||||
|
||||
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY))
|
||||
;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
90
firmware/chibios/os/hal/platforms/AT91SAM7/hal_lld.h
Executable file
90
firmware/chibios/os/hal/platforms/AT91SAM7/hal_lld.h
Executable file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/hal_lld.h
|
||||
* @brief AT91SAM7 HAL subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup HAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _HAL_LLD_H_
|
||||
#define _HAL_LLD_H_
|
||||
|
||||
#include "at91sam7.h"
|
||||
#include "at91lib/aic.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Defines the support for realtime counters in the HAL.
|
||||
*/
|
||||
#define HAL_IMPLEMENTS_COUNTERS FALSE
|
||||
|
||||
/**
|
||||
* @brief Platform name.
|
||||
*/
|
||||
#define PLATFORM_NAME "AT91SAM7x"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Default action for the spurious handler, nothing.
|
||||
*/
|
||||
#if !defined(AT91SAM7_SPURIOUS_HANDLER_HOOK) || defined(__DOXYGEN__)
|
||||
#define AT91SAM7_SPURIOUS_HANDLER_HOOK()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default divider for the USB clock - half the PLL clock.
|
||||
*/
|
||||
#if !defined(AT91SAM7_USBDIV) || defined(__DOXYGEN__)
|
||||
#define AT91SAM7_USBDIV AT91C_CKGR_USBDIV_1
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void hal_lld_init(void);
|
||||
void at91sam7_clock_init(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
464
firmware/chibios/os/hal/platforms/AT91SAM7/i2c_lld.c
Executable file
464
firmware/chibios/os/hal/platforms/AT91SAM7/i2c_lld.c
Executable file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
|
||||
aka barthess.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/i2c_lld.c
|
||||
* @brief AT91SAM7 I2C subsystem low level driver source.
|
||||
* @note I2C peripheral interrupts on AT91SAM7 platform must have highest
|
||||
* priority in system.
|
||||
*
|
||||
* @addtogroup I2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_I2C || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @brief I2C1 driver identifier.*/
|
||||
#if SAM7_I2C_USE_I2C1 || defined(__DOXYGEN__)
|
||||
I2CDriver I2CD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Wakes up the waiting thread.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] msg wakeup message
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define wakeup_isr(i2cp, msg) { \
|
||||
chSysLockFromIsr(); \
|
||||
if ((i2cp)->thread != NULL) { \
|
||||
Thread *tp = (i2cp)->thread; \
|
||||
(i2cp)->thread = NULL; \
|
||||
tp->p_u.rdymsg = (msg); \
|
||||
chSchReadyI(tp); \
|
||||
} \
|
||||
chSysUnlockFromIsr(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void _i2c_lld_serve_rx_interrupt(I2CDriver *i2cp){
|
||||
if (i2cp->rxbytes == 1)
|
||||
AT91C_BASE_TWI->TWI_CR |= AT91C_TWI_STOP;
|
||||
|
||||
*(i2cp->rxbuf) = AT91C_BASE_TWI->TWI_RHR;
|
||||
i2cp->rxbuf++;
|
||||
i2cp->rxbytes--;
|
||||
if (i2cp->rxbytes == 0){
|
||||
AT91C_BASE_TWI->TWI_IDR = AT91C_TWI_RXRDY;
|
||||
AT91C_BASE_TWI->TWI_IER = AT91C_TWI_TXCOMP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function.
|
||||
* @note During write operation you do not need to set STOP manually.
|
||||
* It sets automatically when THR and shift registers becomes empty.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void _i2c_lld_serve_tx_interrupt(I2CDriver *i2cp){
|
||||
|
||||
if (i2cp->txbytes == 0){
|
||||
AT91C_BASE_TWI->TWI_IDR = AT91C_TWI_TXRDY;
|
||||
AT91C_BASE_TWI->TWI_IER = AT91C_TWI_TXCOMP;
|
||||
}
|
||||
else{
|
||||
AT91C_BASE_TWI->TWI_THR = *(i2cp->txbuf);
|
||||
i2cp->txbuf++;
|
||||
i2cp->txbytes--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C shared ISR code.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_serve_interrupt(I2CDriver *i2cp) {
|
||||
|
||||
uint32_t sr;
|
||||
sr = AT91C_BASE_TWI->TWI_SR;
|
||||
/* this masking doing in official Atmel driver. Is it needed ??? */
|
||||
sr &= AT91C_BASE_TWI->TWI_IMR;
|
||||
|
||||
if (sr & AT91C_TWI_NACK){
|
||||
i2cp->errors |= I2CD_ACK_FAILURE;
|
||||
wakeup_isr(i2cp, RDY_RESET);
|
||||
return;
|
||||
}
|
||||
if (sr & AT91C_TWI_RXRDY){
|
||||
_i2c_lld_serve_rx_interrupt(i2cp);
|
||||
}
|
||||
else if (sr & AT91C_TWI_TXRDY){
|
||||
_i2c_lld_serve_tx_interrupt(i2cp);
|
||||
}
|
||||
else if (sr & AT91C_TWI_TXCOMP){
|
||||
AT91C_BASE_TWI->TWI_IDR = AT91C_TWI_TXCOMP;
|
||||
wakeup_isr(i2cp, RDY_OK);
|
||||
}
|
||||
else
|
||||
chDbgPanic("Invalid value");
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAM7_I2C_USE_I2C1 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief I2C1 event interrupt handler.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
CH_IRQ_HANDLER(TWI_IRQHandler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
i2c_lld_serve_interrupt(&I2CD1);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* STM32_I2C_USE_I2C1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level I2C driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_init(void) {
|
||||
|
||||
#if SAM7_I2C_USE_I2C1
|
||||
i2cObjectInit(&I2CD1);
|
||||
I2CD1.thread = NULL;
|
||||
I2CD1.txbuf = NULL;
|
||||
I2CD1.rxbuf = NULL;
|
||||
I2CD1.txbytes = 0;
|
||||
I2CD1.rxbytes = 0;
|
||||
|
||||
#if SAM7_PLATFORM == SAM7S512 || SAM7_PLATFORM == SAM7S256 || SAM7_PLATFORM == SAM7S128 || SAM7_PLATFORM == SAM7S64
|
||||
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_ASR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_MDER = AT91C_PA3_TWD | AT91C_PA4_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
|
||||
#elif SAM7_PLATFORM == SAM7X512 || SAM7_PLATFORM == SAM7X256 || SAM7_PLATFORM == SAM7X128
|
||||
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA10_TWD | AT91C_PA11_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_ASR = AT91C_PA10_TWD | AT91C_PA11_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_MDER = AT91C_PA10_TWD | AT91C_PA11_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA10_TWD | AT91C_PA11_TWCK;
|
||||
#elif SAM7_PLATFORM == SAM7A3
|
||||
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA0_TWD | AT91C_PA1_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_ASR = AT91C_PA0_TWD | AT91C_PA1_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_MDER = AT91C_PA0_TWD | AT91C_PA1_TWCK;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA0_TWD | AT91C_PA1_TWCK;
|
||||
#else
|
||||
#error "SAM7 platform not supported"
|
||||
#endif
|
||||
|
||||
AIC_ConfigureIT(AT91C_ID_TWI,
|
||||
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | SAM7_I2C_I2C1_IRQ_PRIORITY,
|
||||
TWI_IRQHandler);
|
||||
#endif /* STM32_I2C_USE_I2C1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the I2C peripheral.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_start(I2CDriver *i2cp) {
|
||||
|
||||
volatile uint32_t fake;
|
||||
|
||||
/* If in stopped state then enables the I2C clocks.*/
|
||||
if (i2cp->state == I2C_STOP) {
|
||||
|
||||
#if SAM7_I2C_USE_I2C1
|
||||
if (&I2CD1 == i2cp) {
|
||||
/* enable peripheral clock */
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TWI);
|
||||
|
||||
/* Enables associated interrupt vector.*/
|
||||
AIC_EnableIT(AT91C_ID_TWI);
|
||||
|
||||
/* Reset */
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_SWRST;
|
||||
fake = AT91C_BASE_TWI->TWI_RHR;
|
||||
|
||||
/* Set master mode */
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_MSDIS;
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_MSEN;
|
||||
|
||||
/* Setup I2C parameters. */
|
||||
AT91C_BASE_TWI->TWI_CWGR = i2cp->config->cwgr;
|
||||
}
|
||||
#endif /* STM32_I2C_USE_I2C1 */
|
||||
}
|
||||
|
||||
(void)fake;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the I2C peripheral.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_stop(I2CDriver *i2cp) {
|
||||
|
||||
/* If not in stopped state then disables the I2C clock.*/
|
||||
if (i2cp->state != I2C_STOP) {
|
||||
|
||||
#if SAM7_I2C_USE_I2C1
|
||||
if (&I2CD1 == i2cp) {
|
||||
AT91C_BASE_TWI->TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY |
|
||||
AT91C_TWI_TXRDY | AT91C_TWI_NACK;
|
||||
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_TWI);
|
||||
AIC_DisableIT(AT91C_ID_TWI);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receives data via the I2C bus as master.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] addr slave device address
|
||||
* @param[out] rxbuf pointer to the receive buffer
|
||||
* @param[in] rxbytes number of bytes to be received
|
||||
* @param[in] timeout this value is ignored on SAM7 platform.
|
||||
*
|
||||
* @return The operation status.
|
||||
* @retval RDY_OK if the function succeeded.
|
||||
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
|
||||
* be retrieved using @p i2cGetErrors().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout) {
|
||||
(void)timeout;
|
||||
|
||||
/* delete trash from RHR*/
|
||||
volatile uint32_t fake;
|
||||
fake = AT91C_BASE_TWI->TWI_RHR;
|
||||
(void)fake;
|
||||
|
||||
/* Initializes driver fields.*/
|
||||
i2cp->rxbuf = rxbuf;
|
||||
i2cp->rxbytes = rxbytes;
|
||||
|
||||
i2cp->txbuf = NULL;
|
||||
i2cp->txbytes = 0;
|
||||
|
||||
/* tune master mode register */
|
||||
AT91C_BASE_TWI->TWI_MMR = 0;
|
||||
AT91C_BASE_TWI->TWI_MMR |= (addr << 16) | AT91C_TWI_MREAD;
|
||||
|
||||
/* enable just needed interrupts */
|
||||
AT91C_BASE_TWI->TWI_IER = AT91C_TWI_RXRDY | AT91C_TWI_NACK;
|
||||
|
||||
/* In single data byte master read or write, the START and STOP must both be set. */
|
||||
if (rxbytes == 1)
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_STOP | AT91C_TWI_START;
|
||||
else
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_START;
|
||||
|
||||
/* Waits for the operation completion.*/
|
||||
i2cp->thread = chThdSelf();
|
||||
chSchGoSleepS(THD_STATE_SUSPENDED);
|
||||
|
||||
return chThdSelf()->p_u.rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data via the I2C bus as master using internal slave addressing.
|
||||
* @details Address bytes must be written in special purpose SAM7 registers.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] addr slave device address
|
||||
* @param[in] txbuf pointer to the transmit buffer
|
||||
* @param[in] txbytes number of bytes to be transmitted
|
||||
* @param[out] rxbuf pointer to the receive buffer
|
||||
* @param[in] rxbytes number of bytes to be received
|
||||
* @param[in] timeout this value is ignored on SAM7 platform.
|
||||
*
|
||||
* @return The operation status.
|
||||
* @retval RDY_OK if the function succeeded.
|
||||
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
|
||||
* be retrieved using @p i2cGetErrors().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t i2c_lld_transceive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout) {
|
||||
(void)timeout;
|
||||
|
||||
/* delete trash from RHR*/
|
||||
volatile uint32_t fake;
|
||||
fake = AT91C_BASE_TWI->TWI_RHR;
|
||||
(void)fake;
|
||||
|
||||
/* Initializes driver fields.*/
|
||||
i2cp->rxbuf = rxbuf;
|
||||
i2cp->rxbytes = rxbytes;
|
||||
|
||||
/* tune master mode register */
|
||||
AT91C_BASE_TWI->TWI_MMR = 0;
|
||||
AT91C_BASE_TWI->TWI_MMR |= (addr << 16) | (txbytes << 8) | AT91C_TWI_MREAD;
|
||||
|
||||
/* store internal slave address in TWI_IADR registers */
|
||||
AT91C_BASE_TWI->TWI_IADR = 0;
|
||||
while (txbytes > 0){
|
||||
AT91C_BASE_TWI->TWI_IADR = (AT91C_BASE_TWI->TWI_IADR << 8);
|
||||
AT91C_BASE_TWI->TWI_IADR |= *(txbuf++);
|
||||
txbytes--;
|
||||
}
|
||||
|
||||
/* enable just needed interrupts */
|
||||
AT91C_BASE_TWI->TWI_IER = AT91C_TWI_RXRDY | AT91C_TWI_NACK;
|
||||
|
||||
/* Internal address of I2C slave was set in special Atmel registers.
|
||||
* Now we must call read function. The I2C cell automatically sends
|
||||
* bytes from IADR register to bus and issues repeated start. */
|
||||
if (rxbytes == 1)
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_STOP | AT91C_TWI_START;
|
||||
else
|
||||
AT91C_BASE_TWI->TWI_CR = AT91C_TWI_START;
|
||||
|
||||
/* Waits for the operation completion.*/
|
||||
i2cp->thread = chThdSelf();
|
||||
chSchGoSleepS(THD_STATE_SUSPENDED);
|
||||
|
||||
return chThdSelf()->p_u.rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmits data via the I2C bus as master.
|
||||
* @details When performing reading through write you can not write more than
|
||||
* 3 bytes of data to I2C slave. This is SAM7 platform limitation.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] addr slave device address
|
||||
* @param[in] txbuf pointer to the transmit buffer
|
||||
* @param[in] txbytes number of bytes to be transmitted
|
||||
* @param[out] rxbuf pointer to the receive buffer
|
||||
* @param[in] rxbytes number of bytes to be received
|
||||
* @param[in] timeout this value is ignored on SAM7 platform.
|
||||
*
|
||||
* @return The operation status.
|
||||
* @retval RDY_OK if the function succeeded.
|
||||
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
|
||||
* be retrieved using @p i2cGetErrors().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout) {
|
||||
(void)timeout;
|
||||
|
||||
/* SAM7 specific check */
|
||||
chDbgCheck(((rxbytes == 0) ||
|
||||
((txbytes > 0) && (txbytes < 4) && (rxbuf != NULL))),
|
||||
"i2c_lld_master_transmit_timeout");
|
||||
|
||||
/* prepare to read through write operation */
|
||||
if (rxbytes > 0){
|
||||
return i2c_lld_transceive_timeout(i2cp, addr, txbuf, txbytes, rxbuf,
|
||||
rxbytes, timeout);
|
||||
}
|
||||
else{
|
||||
if (txbytes == 1){
|
||||
/* In single data byte master read or write, the START and STOP
|
||||
* must both be set. */
|
||||
AT91C_BASE_TWI->TWI_CR |= AT91C_TWI_STOP;
|
||||
}
|
||||
AT91C_BASE_TWI->TWI_MMR = 0;
|
||||
AT91C_BASE_TWI->TWI_MMR |= addr << 16;
|
||||
|
||||
/* enable just needed interrupts */
|
||||
AT91C_BASE_TWI->TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK;
|
||||
|
||||
/* correct size and pointer because first byte will be written
|
||||
* for issue start condition */
|
||||
i2cp->txbuf = txbuf + 1;
|
||||
i2cp->txbytes = txbytes - 1;
|
||||
|
||||
/* According to datasheet there is no need to set START manually
|
||||
* we just need to write first byte in THR */
|
||||
AT91C_BASE_TWI->TWI_THR = txbuf[0];
|
||||
|
||||
/* Waits for the operation completion.*/
|
||||
i2cp->thread = chThdSelf();
|
||||
chSchGoSleepS(THD_STATE_SUSPENDED);
|
||||
|
||||
return chThdSelf()->p_u.rdymsg;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_I2C */
|
||||
|
||||
/** @} */
|
||||
204
firmware/chibios/os/hal/platforms/AT91SAM7/i2c_lld.h
Executable file
204
firmware/chibios/os/hal/platforms/AT91SAM7/i2c_lld.h
Executable file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
|
||||
aka barthess.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/i2c_lld.h
|
||||
* @brief AT91SAM7 I2C subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup I2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _I2C_LLD_H_
|
||||
#define _I2C_LLD_H_
|
||||
|
||||
#if HAL_USE_I2C || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Peripheral clock frequency.
|
||||
*/
|
||||
#define I2C_CLK_FREQ ((STM32_PCLK1) / 1000000)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief I2C1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for I2C1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAM7_I2C_USE_I2C1) || defined(__DOXYGEN__)
|
||||
#define SAM7_I2C_USE_I2C1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAM7_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAM7_I2C_I2C1_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @brief error checks */
|
||||
#if !SAM7_I2C_USE_I2C1
|
||||
#error "I2C driver activated but no I2C peripheral assigned"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type representing I2C address.
|
||||
*/
|
||||
typedef uint16_t i2caddr_t;
|
||||
|
||||
/**
|
||||
* @brief I2C Driver condition flags type.
|
||||
*/
|
||||
typedef uint32_t i2cflags_t;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief CWGR regitster content.
|
||||
*/
|
||||
uint32_t cwgr;
|
||||
} I2CConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an I2C driver.
|
||||
*/
|
||||
typedef struct I2CDriver I2CDriver;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an I2C driver.
|
||||
*/
|
||||
struct I2CDriver{
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
i2cstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const I2CConfig *config;
|
||||
/**
|
||||
* @brief Error flags.
|
||||
*/
|
||||
i2cflags_t errors;
|
||||
/**
|
||||
* @brief Pointer to receive buffer.
|
||||
*/
|
||||
uint8_t *rxbuf;
|
||||
/**
|
||||
* @brief Pointer to transmit buffer.
|
||||
*/
|
||||
const uint8_t *txbuf;
|
||||
/**
|
||||
* @brief Bytes count to be received.
|
||||
*/
|
||||
size_t rxbytes;
|
||||
/**
|
||||
* @brief Bytes count to be transmitted.
|
||||
*/
|
||||
size_t txbytes;
|
||||
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the bus.
|
||||
*/
|
||||
Mutex mutex;
|
||||
#elif CH_USE_SEMAPHORES
|
||||
Semaphore semaphore;
|
||||
#endif
|
||||
#endif /* I2C_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(I2C_DRIVER_EXT_FIELDS)
|
||||
I2C_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Thread waiting for I/O completion.
|
||||
*/
|
||||
Thread *thread;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Get errors from I2C driver.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
#if SAM7_I2C_USE_I2C1
|
||||
extern I2CDriver I2CD1;
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void i2c_lld_init(void);
|
||||
void i2c_lld_start(I2CDriver *i2cp);
|
||||
void i2c_lld_stop(I2CDriver *i2cp);
|
||||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout);
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_I2C */
|
||||
|
||||
#endif /* _I2C_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
551
firmware/chibios/os/hal/platforms/AT91SAM7/mac_lld.c
Executable file
551
firmware/chibios/os/hal/platforms/AT91SAM7/mac_lld.c
Executable file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/mac_lld.c
|
||||
* @brief AT91SAM7 low level MAC driver code.
|
||||
*
|
||||
* @addtogroup MAC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "mii.h"
|
||||
#include "at91sam7_mii.h"
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
#define EMAC_PIN_MASK (AT91C_PB0_ETXCK_EREFCK | AT91C_PB1_ETXEN | \
|
||||
AT91C_PB2_ETX0 | AT91C_PB3_ETX1 | \
|
||||
AT91C_PB4_ECRS | AT91C_PB5_ERX0 | \
|
||||
AT91C_PB6_ERX1 | AT91C_PB7_ERXER | \
|
||||
AT91C_PB8_EMDC | AT91C_PB9_EMDIO | \
|
||||
AT91C_PB10_ETX2 | AT91C_PB11_ETX3 | \
|
||||
AT91C_PB12_ETXER | AT91C_PB13_ERX2 | \
|
||||
AT91C_PB14_ERX3 | AT91C_PB15_ERXDV_ECRSDV | \
|
||||
AT91C_PB16_ECOL | AT91C_PB17_ERXCK)
|
||||
|
||||
#define RSR_BITS (AT91C_EMAC_BNA | AT91C_EMAC_REC | AT91C_EMAC_OVR)
|
||||
|
||||
#define TSR_BITS (AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES | \
|
||||
AT91C_EMAC_BEX | AT91C_EMAC_COMP | AT91C_EMAC_UND)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Ethernet driver 1.
|
||||
*/
|
||||
MACDriver ETHD1;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
|
||||
static uint8_t default_mac[] = {0xAA, 0x55, 0x13, 0x37, 0x01, 0x10};
|
||||
|
||||
static EMACDescriptor *rxptr;
|
||||
static EMACDescriptor *txptr;
|
||||
static EMACDescriptor rd[EMAC_RECEIVE_DESCRIPTORS]
|
||||
__attribute__((aligned(8)));
|
||||
static EMACDescriptor td[EMAC_TRANSMIT_DESCRIPTORS]
|
||||
__attribute__((aligned(8)));
|
||||
static uint8_t rb[EMAC_RECEIVE_DESCRIPTORS * EMAC_RECEIVE_BUFFERS_SIZE]
|
||||
__attribute__((aligned(8)));
|
||||
static uint8_t tb[EMAC_TRANSMIT_DESCRIPTORS * EMAC_TRANSMIT_BUFFERS_SIZE]
|
||||
__attribute__((aligned(8)));
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief IRQ handler.
|
||||
*/
|
||||
/** @cond never*/
|
||||
__attribute__((noinline))
|
||||
/** @endcond*/
|
||||
static void serve_interrupt(void) {
|
||||
uint32_t isr, rsr, tsr;
|
||||
|
||||
/* Fix for the EMAC errata */
|
||||
isr = AT91C_BASE_EMAC->EMAC_ISR;
|
||||
rsr = AT91C_BASE_EMAC->EMAC_RSR;
|
||||
tsr = AT91C_BASE_EMAC->EMAC_TSR;
|
||||
|
||||
if ((isr & AT91C_EMAC_RCOMP) || (rsr & RSR_BITS)) {
|
||||
if (rsr & AT91C_EMAC_REC) {
|
||||
chSysLockFromIsr();
|
||||
chSemResetI(ÐD1.rdsem, 0);
|
||||
#if MAC_USE_EVENTS
|
||||
chEvtBroadcastI(ÐD1.rdevent);
|
||||
#endif
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
AT91C_BASE_EMAC->EMAC_RSR = RSR_BITS;
|
||||
}
|
||||
|
||||
if ((isr & AT91C_EMAC_TCOMP) || (tsr & TSR_BITS)) {
|
||||
if (tsr & AT91C_EMAC_COMP) {
|
||||
chSysLockFromIsr();
|
||||
chSemResetI(ÐD1.tdsem, 0);
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
AT91C_BASE_EMAC->EMAC_TSR = TSR_BITS;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleans an incomplete frame.
|
||||
*
|
||||
* @param[in] from the start position of the incomplete frame
|
||||
*/
|
||||
static void cleanup(EMACDescriptor *from) {
|
||||
|
||||
while (from != rxptr) {
|
||||
from->w1 &= ~W1_R_OWNERSHIP;
|
||||
if (++from >= &rd[EMAC_RECEIVE_DESCRIPTORS])
|
||||
from = rd;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MAC address setup.
|
||||
*
|
||||
* @param[in] p pointer to a six bytes buffer containing the MAC
|
||||
* address
|
||||
*/
|
||||
static void set_address(const uint8_t *p) {
|
||||
|
||||
AT91C_BASE_EMAC->EMAC_SA1L = (AT91_REG)((p[3] << 24) | (p[2] << 16) |
|
||||
(p[1] << 8) | p[0]);
|
||||
AT91C_BASE_EMAC->EMAC_SA1H = (AT91_REG)((p[5] << 8) | p[4]);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EMAC IRQ handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(irq_handler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
serve_interrupt();
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level MAC initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_init(void) {
|
||||
|
||||
miiInit();
|
||||
macObjectInit(ÐD1);
|
||||
|
||||
/*
|
||||
* Associated PHY initialization.
|
||||
*/
|
||||
miiReset(ÐD1);
|
||||
|
||||
/*
|
||||
* EMAC pins setup. Note, PB18 is not included because it is
|
||||
* used as #PD control and not as EF100.
|
||||
*/
|
||||
AT91C_BASE_PIOB->PIO_ASR = EMAC_PIN_MASK;
|
||||
AT91C_BASE_PIOB->PIO_PDR = EMAC_PIN_MASK;
|
||||
AT91C_BASE_PIOB->PIO_PPUDR = EMAC_PIN_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the MAC peripheral.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_start(MACDriver *macp) {
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* Buffers initialization.
|
||||
*/
|
||||
for (i = 0; i < EMAC_RECEIVE_DESCRIPTORS; i++) {
|
||||
rd[i].w1 = (uint32_t)&rb[i * EMAC_RECEIVE_BUFFERS_SIZE];
|
||||
rd[i].w2 = 0;
|
||||
}
|
||||
rd[EMAC_RECEIVE_DESCRIPTORS - 1].w1 |= W1_R_WRAP;
|
||||
rxptr = rd;
|
||||
for (i = 0; i < EMAC_TRANSMIT_DESCRIPTORS; i++) {
|
||||
td[i].w1 = (uint32_t)&tb[i * EMAC_TRANSMIT_BUFFERS_SIZE];
|
||||
td[i].w2 = EMAC_TRANSMIT_BUFFERS_SIZE | W2_T_LAST_BUFFER | W2_T_USED;
|
||||
}
|
||||
td[EMAC_TRANSMIT_DESCRIPTORS - 1].w2 |= W2_T_WRAP;
|
||||
txptr = td;
|
||||
|
||||
/*
|
||||
* EMAC clock enable.
|
||||
*/
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_EMAC;
|
||||
|
||||
/*
|
||||
* EMAC Initial setup.
|
||||
*/
|
||||
AT91C_BASE_EMAC->EMAC_NCR = 0; /* Stopped but MCE active.*/
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR = 2 << 10; /* MDC-CLK = MCK / 32 */
|
||||
AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;/* Enable EMAC in MII mode.*/
|
||||
AT91C_BASE_EMAC->EMAC_RBQP = (AT91_REG)rd; /* RX descriptors list.*/
|
||||
AT91C_BASE_EMAC->EMAC_TBQP = (AT91_REG)td; /* TX descriptors list.*/
|
||||
AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_OVR |
|
||||
AT91C_EMAC_REC |
|
||||
AT91C_EMAC_BNA; /* Clears RSR.*/
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_DRFCS;/* Initial NCFGR settings.*/
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE |
|
||||
AT91C_EMAC_RE |
|
||||
AT91C_EMAC_CLRSTAT;/* Initial NCR settings.*/
|
||||
if (macp->config->mac_address == NULL)
|
||||
set_address(default_mac);
|
||||
else
|
||||
set_address(macp->config->mac_address);
|
||||
|
||||
/*
|
||||
* PHY device identification.
|
||||
*/
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
|
||||
if ((miiGet(ÐD1, MII_PHYSID1) != (PHY_ID >> 16)) ||
|
||||
((miiGet(ÐD1, MII_PHYSID2) & 0xFFF0) != (PHY_ID & 0xFFF0)))
|
||||
chSysHalt();
|
||||
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||
|
||||
/*
|
||||
* Interrupt configuration.
|
||||
*/
|
||||
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
|
||||
AIC_ConfigureIT(AT91C_ID_EMAC,
|
||||
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | EMAC_INTERRUPT_PRIORITY,
|
||||
irq_handler);
|
||||
AIC_EnableIT(AT91C_ID_EMAC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the MAC peripheral.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_stop(MACDriver *macp) {
|
||||
|
||||
(void)macp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a transmission descriptor.
|
||||
* @details One of the available transmission descriptors is locked and
|
||||
* returned.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[out] tdp pointer to a @p MACTransmitDescriptor structure
|
||||
* @return The operation status.
|
||||
* @retval RDY_OK the descriptor has been obtained.
|
||||
* @retval RDY_TIMEOUT descriptor not available.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||
MACTransmitDescriptor *tdp) {
|
||||
EMACDescriptor *edp;
|
||||
|
||||
(void)macp;
|
||||
|
||||
if (!macp->link_up)
|
||||
return RDY_TIMEOUT;
|
||||
|
||||
chSysLock();
|
||||
edp = txptr;
|
||||
if (!(edp->w2 & W2_T_USED) || (edp->w2 & W2_T_LOCKED)) {
|
||||
chSysUnlock();
|
||||
return RDY_TIMEOUT;
|
||||
}
|
||||
/*
|
||||
* Set the buffer size and configuration, the buffer is also marked
|
||||
* as locked.
|
||||
*/
|
||||
if (++txptr >= &td[EMAC_TRANSMIT_DESCRIPTORS]) {
|
||||
edp->w2 = W2_T_LOCKED | W2_T_USED | W2_T_LAST_BUFFER | W2_T_WRAP;
|
||||
txptr = td;
|
||||
}
|
||||
else
|
||||
edp->w2 = W2_T_LOCKED | W2_T_USED | W2_T_LAST_BUFFER;
|
||||
chSysUnlock();
|
||||
tdp->offset = 0;
|
||||
tdp->size = EMAC_TRANSMIT_BUFFERS_SIZE;
|
||||
tdp->physdesc = edp;
|
||||
return RDY_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes to a transmit descriptor's stream.
|
||||
*
|
||||
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
|
||||
* @param[in] buf pointer to the buffer containing the data to be
|
||||
* written
|
||||
* @param[in] size number of bytes to be written
|
||||
* @return The number of bytes written into the descriptor's
|
||||
* stream, this value can be less than the amount
|
||||
* specified in the parameter @p size if the maximum
|
||||
* frame size is reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||
uint8_t *buf,
|
||||
size_t size) {
|
||||
|
||||
if (size > tdp->size - tdp->offset)
|
||||
size = tdp->size - tdp->offset;
|
||||
if (size > 0) {
|
||||
memcpy((uint8_t *)(tdp->physdesc->w1 & W1_T_ADDRESS_MASK) +
|
||||
tdp->offset,
|
||||
buf, size);
|
||||
tdp->offset += size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a transmit descriptor and starts the transmission of the
|
||||
* enqueued data as a single frame.
|
||||
*
|
||||
* @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
|
||||
|
||||
chSysLock();
|
||||
tdp->physdesc->w2 = (tdp->physdesc->w2 &
|
||||
~(W2_T_LOCKED | W2_T_USED | W2_T_LENGTH_MASK)) |
|
||||
tdp->offset;
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a receive descriptor.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[out] rdp pointer to a @p MACReceiveDescriptor structure
|
||||
* @return The operation status.
|
||||
* @retval RDY_OK the descriptor has been obtained.
|
||||
* @retval RDY_TIMEOUT descriptor not available.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||
MACReceiveDescriptor *rdp) {
|
||||
unsigned n;
|
||||
EMACDescriptor *edp;
|
||||
|
||||
(void)macp;
|
||||
n = EMAC_RECEIVE_DESCRIPTORS;
|
||||
|
||||
/*
|
||||
* Skips unused buffers, if any.
|
||||
*/
|
||||
skip:
|
||||
while ((n > 0) && !(rxptr->w1 & W1_R_OWNERSHIP)) {
|
||||
if (++rxptr >= &rd[EMAC_RECEIVE_DESCRIPTORS])
|
||||
rxptr = rd;
|
||||
n--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skips fragments, if any, cleaning them up.
|
||||
*/
|
||||
while ((n > 0) && (rxptr->w1 & W1_R_OWNERSHIP) &&
|
||||
!(rxptr->w2 & W2_R_FRAME_START)) {
|
||||
rxptr->w1 &= ~W1_R_OWNERSHIP;
|
||||
if (++rxptr >= &rd[EMAC_RECEIVE_DESCRIPTORS])
|
||||
rxptr = rd;
|
||||
n--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now compute the total frame size skipping eventual incomplete frames
|
||||
* or holes...
|
||||
*/
|
||||
restart:
|
||||
edp = rxptr;
|
||||
while (n > 0) {
|
||||
if (!(rxptr->w1 & W1_R_OWNERSHIP)) {
|
||||
/* Empty buffer for some reason... cleaning up the incomplete frame.*/
|
||||
cleanup(edp);
|
||||
goto skip;
|
||||
}
|
||||
/*
|
||||
* End Of Frame found.
|
||||
*/
|
||||
if (rxptr->w2 & W2_R_FRAME_END) {
|
||||
rdp->offset = 0;
|
||||
rdp->size = rxptr->w2 & W2_T_LENGTH_MASK;
|
||||
rdp->physdesc = edp;
|
||||
return RDY_OK;
|
||||
}
|
||||
|
||||
if ((edp != rxptr) && (rxptr->w2 & W2_R_FRAME_START)) {
|
||||
/* Found another start... cleaning up the incomplete frame.*/
|
||||
cleanup(edp);
|
||||
goto restart; /* Another start buffer for some reason... */
|
||||
}
|
||||
|
||||
if (++rxptr >= &rd[EMAC_RECEIVE_DESCRIPTORS])
|
||||
rxptr = rd;
|
||||
n--;
|
||||
}
|
||||
return RDY_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads from a receive descriptor's stream.
|
||||
*
|
||||
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
|
||||
* @param[in] buf pointer to the buffer that will receive the read data
|
||||
* @param[in] size number of bytes to be read
|
||||
* @return The number of bytes read from the descriptor's
|
||||
* stream, this value can be less than the amount
|
||||
* specified in the parameter @p size if there are
|
||||
* no more bytes to read.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||
uint8_t *buf,
|
||||
size_t size) {
|
||||
if (size > rdp->size - rdp->offset)
|
||||
size = rdp->size - rdp->offset;
|
||||
if (size > 0) {
|
||||
uint8_t *src = (uint8_t *)(rdp->physdesc->w1 & W1_R_ADDRESS_MASK) +
|
||||
rdp->offset;
|
||||
uint8_t *limit = &rb[EMAC_RECEIVE_DESCRIPTORS * EMAC_RECEIVE_BUFFERS_SIZE];
|
||||
if (src >= limit)
|
||||
src -= EMAC_RECEIVE_DESCRIPTORS * EMAC_RECEIVE_BUFFERS_SIZE;
|
||||
if (src + size > limit ) {
|
||||
memcpy(buf, src, (size_t)(limit - src));
|
||||
memcpy(buf + (size_t)(limit - src), rb, size - (size_t)(limit - src));
|
||||
}
|
||||
else
|
||||
memcpy(buf, src, size);
|
||||
rdp->offset += size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a receive descriptor.
|
||||
* @details The descriptor and its buffer are made available for more incoming
|
||||
* frames.
|
||||
*
|
||||
* @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
|
||||
bool_t done;
|
||||
EMACDescriptor *edp = rdp->physdesc;
|
||||
|
||||
unsigned n = EMAC_RECEIVE_DESCRIPTORS;
|
||||
do {
|
||||
done = ((edp->w2 & W2_R_FRAME_END) != 0);
|
||||
chDbgAssert(edp->w1 & W1_R_OWNERSHIP,
|
||||
"mac_lld_release_receive_descriptor(), #1",
|
||||
"found not owned descriptor");
|
||||
edp->w1 &= ~(W1_R_OWNERSHIP | W2_R_FRAME_START | W2_R_FRAME_END);
|
||||
if (++edp >= &rd[EMAC_RECEIVE_DESCRIPTORS])
|
||||
edp = rd;
|
||||
n--;
|
||||
}
|
||||
while ((n > 0) && !done);
|
||||
/*
|
||||
* Make rxptr point to the descriptor where the next frame will most
|
||||
* likely appear.
|
||||
*/
|
||||
rxptr = edp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates and returns the link status.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @return The link status.
|
||||
* @retval TRUE if the link is active.
|
||||
* @retval FALSE if the link is down.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
bool_t mac_lld_poll_link_status(MACDriver *macp) {
|
||||
uint32_t ncfgr, bmsr, bmcr, lpa;
|
||||
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
|
||||
(void)miiGet(macp, MII_BMSR);
|
||||
bmsr = miiGet(macp, MII_BMSR);
|
||||
if (!(bmsr & BMSR_LSTATUS)) {
|
||||
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||
return macp->link_up = FALSE;
|
||||
}
|
||||
|
||||
ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
|
||||
bmcr = miiGet(macp, MII_BMCR);
|
||||
if (bmcr & BMCR_ANENABLE) {
|
||||
lpa = miiGet(macp, MII_LPA);
|
||||
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
|
||||
ncfgr |= AT91C_EMAC_SPD;
|
||||
if (lpa & (LPA_10FULL | LPA_100FULL))
|
||||
ncfgr |= AT91C_EMAC_FD;
|
||||
}
|
||||
else {
|
||||
if (bmcr & BMCR_SPEED100)
|
||||
ncfgr |= AT91C_EMAC_SPD;
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
ncfgr |= AT91C_EMAC_FD;
|
||||
}
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr;
|
||||
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||
return macp->link_up = TRUE;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
/** @} */
|
||||
252
firmware/chibios/os/hal/platforms/AT91SAM7/mac_lld.h
Executable file
252
firmware/chibios/os/hal/platforms/AT91SAM7/mac_lld.h
Executable file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/mac_lld.h
|
||||
* @brief AT91SAM7 low level MAC driver header.
|
||||
*
|
||||
* @addtogroup MAC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _MAC_LLD_H_
|
||||
#define _MAC_LLD_H_
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief This implementation does not support the zero-copy mode API.
|
||||
*/
|
||||
#define MAC_SUPPORTS_ZERO_COPY FALSE
|
||||
|
||||
#define EMAC_RECEIVE_BUFFERS_SIZE 128 /* Do not modify */
|
||||
#define EMAC_TRANSMIT_BUFFERS_SIZE MAC_BUFFERS_SIZE
|
||||
#define EMAC_RECEIVE_DESCRIPTORS \
|
||||
(((((MAC_BUFFERS_SIZE - 1) | (EMAC_RECEIVE_BUFFERS_SIZE - 1)) + 1) \
|
||||
/ EMAC_RECEIVE_BUFFERS_SIZE) * MAC_RECEIVE_BUFFERS)
|
||||
#define EMAC_TRANSMIT_DESCRIPTORS MAC_TRANSMIT_BUFFERS
|
||||
|
||||
#define W1_R_OWNERSHIP 0x00000001
|
||||
#define W1_R_WRAP 0x00000002
|
||||
#define W1_R_ADDRESS_MASK 0xFFFFFFFC
|
||||
|
||||
#define W2_R_LENGTH_MASK 0x00000FFF
|
||||
#define W2_R_FRAME_START 0x00004000
|
||||
#define W2_R_FRAME_END 0x00008000
|
||||
#define W2_R_CFI 0x00010000
|
||||
#define W2_R_VLAN_PRIO_MASK 0x000E0000
|
||||
#define W2_R_PRIO_TAG_DETECTED 0x00100000
|
||||
#define W2_R_VLAN_TAG_DETECTED 0x00200000
|
||||
#define W2_R_TYPE_ID_MATCH 0x00400000
|
||||
#define W2_R_ADDR4_MATCH 0x00800000
|
||||
#define W2_R_ADDR3_MATCH 0x01000000
|
||||
#define W2_R_ADDR2_MATCH 0x02000000
|
||||
#define W2_R_ADDR1_MATCH 0x04000000
|
||||
#define W2_R_RFU1 0x08000000
|
||||
#define W2_R_ADDR_EXT_MATCH 0x10000000
|
||||
#define W2_R_UNICAST_MATCH 0x20000000
|
||||
#define W2_R_MULTICAST_MATCH 0x40000000
|
||||
#define W2_R_BROADCAST_DETECTED 0x80000000
|
||||
|
||||
#define W1_T_ADDRESS_MASK 0xFFFFFFFF
|
||||
|
||||
#define W2_T_LENGTH_MASK 0x000007FF
|
||||
#define W2_T_LOCKED 0x00000800 /* Not an EMAC flag. */
|
||||
#define W2_T_RFU1 0x00003000
|
||||
#define W2_T_LAST_BUFFER 0x00008000
|
||||
#define W2_T_NO_CRC 0x00010000
|
||||
#define W2_T_RFU2 0x07FE0000
|
||||
#define W2_T_BUFFERS_EXHAUSTED 0x08000000
|
||||
#define W2_T_TRANSMIT_UNDERRUN 0x10000000
|
||||
#define W2_T_RETRY_LIMIT_EXC 0x20000000
|
||||
#define W2_T_WRAP 0x40000000
|
||||
#define W2_T_USED 0x80000000
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of available transmit buffers.
|
||||
*/
|
||||
#if !defined(MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
|
||||
#define MAC_TRANSMIT_BUFFERS 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of available receive buffers.
|
||||
*/
|
||||
#if !defined(MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
|
||||
#define MAC_RECEIVE_BUFFERS 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum supported frame size.
|
||||
*/
|
||||
#if !defined(MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||
#define MAC_BUFFERS_SIZE 1518
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Interrupt priority level for the EMAC device.
|
||||
*/
|
||||
#if !defined(EMAC_INTERRUPT_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define EMAC_INTERRUPT_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 3)
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure representing a buffer physical descriptor.
|
||||
* @note It represents both descriptor types.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t w1;
|
||||
uint32_t w2;
|
||||
} EMACDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief MAC address.
|
||||
*/
|
||||
const uint8_t *mac_address;
|
||||
/* End of the mandatory fields.*/
|
||||
} MACConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a MAC driver.
|
||||
*/
|
||||
struct MACDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
macstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const MACConfig *config;
|
||||
/**
|
||||
* @brief Transmit semaphore.
|
||||
*/
|
||||
Semaphore tdsem;
|
||||
/**
|
||||
* @brief Receive semaphore.
|
||||
*/
|
||||
Semaphore rdsem;
|
||||
#if MAC_USE_EVENTS || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Receive event.
|
||||
*/
|
||||
EventSource rdevent;
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Link status flag.
|
||||
*/
|
||||
bool_t link_up;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure representing a transmit descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Current write offset.
|
||||
*/
|
||||
size_t offset;
|
||||
/**
|
||||
* @brief Available space size.
|
||||
*/
|
||||
size_t size;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the physical descriptor.
|
||||
*/
|
||||
EMACDescriptor *physdesc;
|
||||
} MACTransmitDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a receive descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Current read offset.
|
||||
*/
|
||||
size_t offset;
|
||||
/**
|
||||
* @brief Available data size.
|
||||
*/
|
||||
size_t size;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the first descriptor of the buffers chain.
|
||||
*/
|
||||
EMACDescriptor *physdesc;
|
||||
} MACReceiveDescriptor;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern MACDriver ETHD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void mac_lld_init(void);
|
||||
void mac_lld_start(MACDriver *macp);
|
||||
void mac_lld_stop(MACDriver *macp);
|
||||
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||
MACTransmitDescriptor *tdp);
|
||||
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||
uint8_t *buf,
|
||||
size_t size);
|
||||
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
|
||||
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||
MACReceiveDescriptor *rdp);
|
||||
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||
uint8_t *buf,
|
||||
size_t size);
|
||||
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
|
||||
bool_t mac_lld_poll_link_status(MACDriver *macp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
#endif /* _MAC_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
159
firmware/chibios/os/hal/platforms/AT91SAM7/pal_lld.c
Executable file
159
firmware/chibios/os/hal/platforms/AT91SAM7/pal_lld.c
Executable file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/pal_lld.c
|
||||
* @brief AT91SAM7 PIO low level driver code.
|
||||
*
|
||||
* @addtogroup PAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief AT91SAM7 I/O ports configuration.
|
||||
* @details PIO registers initialization.
|
||||
*
|
||||
* @param[in] config the AT91SAM7 ports configuration
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_init(const PALConfig *config) {
|
||||
|
||||
uint32_t ports = (1 << AT91C_ID_PIOA);
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
ports |= (1 << AT91C_ID_PIOB);
|
||||
#endif
|
||||
AT91C_BASE_PMC->PMC_PCER = ports;
|
||||
|
||||
/*
|
||||
* PIOA setup.
|
||||
*/
|
||||
AT91C_BASE_PIOA->PIO_PPUER = config->P0Data.pusr; /* Pull-up as spec.*/
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = ~config->P0Data.pusr;
|
||||
AT91C_BASE_PIOA->PIO_PER = 0xFFFFFFFF; /* PIO enabled.*/
|
||||
AT91C_BASE_PIOA->PIO_ODSR = config->P0Data.odsr; /* Data as specified.*/
|
||||
AT91C_BASE_PIOA->PIO_OER = config->P0Data.osr; /* Dir. as specified.*/
|
||||
AT91C_BASE_PIOA->PIO_ODR = ~config->P0Data.osr;
|
||||
AT91C_BASE_PIOA->PIO_IFDR = 0xFFFFFFFF; /* Filter disabled.*/
|
||||
AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF; /* Int. disabled.*/
|
||||
AT91C_BASE_PIOA->PIO_MDDR = 0xFFFFFFFF; /* Push Pull drive.*/
|
||||
AT91C_BASE_PIOA->PIO_ASR = 0xFFFFFFFF; /* Peripheral A.*/
|
||||
AT91C_BASE_PIOA->PIO_OWER = 0xFFFFFFFF; /* Write enabled.*/
|
||||
|
||||
/*
|
||||
* PIOB setup.
|
||||
*/
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3)
|
||||
AT91C_BASE_PIOB->PIO_PPUER = config->P1Data.pusr; /* Pull-up as spec.*/
|
||||
AT91C_BASE_PIOB->PIO_PPUDR = ~config->P1Data.pusr;
|
||||
AT91C_BASE_PIOB->PIO_PER = 0xFFFFFFFF; /* PIO enabled.*/
|
||||
AT91C_BASE_PIOB->PIO_ODSR = config->P1Data.odsr; /* Data as specified.*/
|
||||
AT91C_BASE_PIOB->PIO_OER = config->P1Data.osr; /* Dir. as specified.*/
|
||||
AT91C_BASE_PIOB->PIO_ODR = ~config->P1Data.osr;
|
||||
AT91C_BASE_PIOB->PIO_IFDR = 0xFFFFFFFF; /* Filter disabled.*/
|
||||
AT91C_BASE_PIOB->PIO_IDR = 0xFFFFFFFF; /* Int. disabled.*/
|
||||
AT91C_BASE_PIOB->PIO_MDDR = 0xFFFFFFFF; /* Push Pull drive.*/
|
||||
AT91C_BASE_PIOB->PIO_ASR = 0xFFFFFFFF; /* Peripheral A.*/
|
||||
AT91C_BASE_PIOB->PIO_OWER = 0xFFFFFFFF; /* Write enabled.*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pads mode setup.
|
||||
* @details This function programs a pads group belonging to the same port
|
||||
* with the specified mode.
|
||||
* @note This function is not meant to be invoked directly from the
|
||||
* application code.
|
||||
* @note @p PAL_MODE_RESET is implemented as input with pull-up.
|
||||
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
|
||||
* high state.
|
||||
* @note @p PAL_MODE_OUTPUT_OPENDRAIN also enables the pull-up resistor.
|
||||
*
|
||||
* @param[in] port the port identifier
|
||||
* @param[in] mask the group mask
|
||||
* @param[in] mode the mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_setgroupmode(ioportid_t port,
|
||||
ioportmask_t mask,
|
||||
iomode_t mode) {
|
||||
|
||||
if (mode & AT91_PAL_OPENDRAIN)
|
||||
port->PIO_MDER = mask;
|
||||
else
|
||||
port->PIO_MDDR = mask;
|
||||
if (mode & AT91_PAL_PULLUP)
|
||||
port->PIO_PPUER = mask;
|
||||
else
|
||||
port->PIO_PPUDR = mask;
|
||||
if (mode & AT91_PAL_OUT_SET)
|
||||
port->PIO_SODR = mask;
|
||||
if (mode & AT91_PAL_OUT_CLEAR)
|
||||
port->PIO_CODR = mask;
|
||||
|
||||
switch (mode & AT91_PAL_DIR_MASK) {
|
||||
case AT91_PAL_DIR_INPUT:
|
||||
port->PIO_ODR = mask;
|
||||
port->PIO_PER = mask;
|
||||
break;
|
||||
case AT91_PAL_DIR_OUTPUT:
|
||||
port->PIO_OER = mask;
|
||||
port->PIO_PER = mask;
|
||||
break;
|
||||
case AT91_PAL_DIR_PERIPH_A:
|
||||
port->PIO_OER = mask;
|
||||
port->PIO_PDR = mask;
|
||||
port->PIO_ASR = mask;
|
||||
break;
|
||||
case AT91_PAL_DIR_PERIPH_B:
|
||||
port->PIO_OER = mask;
|
||||
port->PIO_PDR = mask;
|
||||
port->PIO_BSR = mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
/** @} */
|
||||
292
firmware/chibios/os/hal/platforms/AT91SAM7/pal_lld.h
Executable file
292
firmware/chibios/os/hal/platforms/AT91SAM7/pal_lld.h
Executable file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/pal_lld.h
|
||||
* @brief AT91SAM7 PIO low level driver header.
|
||||
*
|
||||
* @addtogroup PAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _PAL_LLD_H_
|
||||
#define _PAL_LLD_H_
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Unsupported modes and specific modes */
|
||||
/*===========================================================================*/
|
||||
|
||||
// AT91: Port direction
|
||||
#define AT91_PAL_DIR_MASK 0x03
|
||||
#define AT91_PAL_DIR_INPUT 0x00
|
||||
#define AT91_PAL_DIR_OUTPUT 0x01
|
||||
#define AT91_PAL_DIR_PERIPH_A 0x02
|
||||
#define AT91_PAL_DIR_PERIPH_B 0x03
|
||||
|
||||
// AT91: Additional flags
|
||||
#define AT91_PAL_OUT_SET 0x04
|
||||
#define AT91_PAL_OUT_CLEAR 0x08
|
||||
#define AT91_PAL_PULLUP 0x10
|
||||
#define AT91_PAL_OPENDRAIN 0x20
|
||||
|
||||
// Unsupported
|
||||
#undef PAL_MODE_INPUT_PULLDOWN
|
||||
|
||||
// Redefine the standard io modes
|
||||
#undef PAL_MODE_RESET
|
||||
#undef PAL_MODE_UNCONNECTED
|
||||
#undef PAL_MODE_INPUT
|
||||
#undef PAL_MODE_INPUT_PULLUP
|
||||
#undef PAL_MODE_INPUT_ANALOG
|
||||
#undef PAL_MODE_OUTPUT_PUSHPULL
|
||||
#undef PAL_MODE_OUTPUT_OPENDRAIN
|
||||
#define PAL_MODE_RESET (AT91_PAL_DIR_INPUT|AT91_PAL_PULLUP)
|
||||
#define PAL_MODE_UNCONNECTED (AT91_PAL_DIR_OUTPUT|AT91_PAL_OUT_SET)
|
||||
#define PAL_MODE_INPUT (AT91_PAL_DIR_INPUT)
|
||||
#define PAL_MODE_INPUT_PULLUP (AT91_PAL_DIR_INPUT|AT91_PAL_PULLUP)
|
||||
#define PAL_MODE_INPUT_ANALOG (AT91_PAL_DIR_INPUT)
|
||||
#define PAL_MODE_OUTPUT_PUSHPULL (AT91_PAL_DIR_OUTPUT)
|
||||
#define PAL_MODE_OUTPUT_OPENDRAIN (AT91_PAL_DIR_OUTPUT|AT91_PAL_PULLUP|AT91_PAL_OPENDRAIN)
|
||||
|
||||
// Add the AT91 specific ones
|
||||
#define PAL_MODE_PERIPH_A_PUSHPULL (AT91_PAL_DIR_PERIPH_A)
|
||||
#define PAL_MODE_PERIPH_A_OPENDRAIN (AT91_PAL_DIR_PERIPH_A|AT91_PAL_PULLUP|AT91_PAL_OPENDRAIN)
|
||||
#define PAL_MODE_PERIPH_B_PUSHPULL (AT91_PAL_DIR_PERIPH_A)
|
||||
#define PAL_MODE_PERIPH_B_OPENDRAIN (AT91_PAL_DIR_PERIPH_A|AT91_PAL_PULLUP|AT91_PAL_OPENDRAIN)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Types and constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief PIO port setup info.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Initial value for ODSR register (data).*/
|
||||
uint32_t odsr;
|
||||
/** Initial value for OSR register (direction).*/
|
||||
uint32_t osr;
|
||||
/** Initial value for PUSR register (Pull-ups).*/
|
||||
uint32_t pusr;
|
||||
} at91sam7_pio_setup_t;
|
||||
|
||||
/**
|
||||
* @brief AT91SAM7 PIO static initializer.
|
||||
* @details An instance of this structure must be passed to @p palInit() at
|
||||
* system startup time in order to initialize the digital I/O
|
||||
* subsystem. This represents only the initial setup, specific pads
|
||||
* or whole ports can be reprogrammed at later time.
|
||||
*/
|
||||
typedef struct {
|
||||
/** @brief Port 0 setup data.*/
|
||||
at91sam7_pio_setup_t P0Data;
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3) || \
|
||||
defined(__DOXYGEN__)
|
||||
/** @brief Port 1 setup data.*/
|
||||
at91sam7_pio_setup_t P1Data;
|
||||
#endif
|
||||
} PALConfig;
|
||||
|
||||
/**
|
||||
* @brief Width, in bits, of an I/O port.
|
||||
*/
|
||||
#define PAL_IOPORTS_WIDTH 32
|
||||
|
||||
/**
|
||||
* @brief Whole port mask.
|
||||
* @details This macro specifies all the valid bits into a port.
|
||||
*/
|
||||
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
|
||||
|
||||
/**
|
||||
* @brief Digital I/O port sized unsigned type.
|
||||
*/
|
||||
typedef uint32_t ioportmask_t;
|
||||
|
||||
/**
|
||||
* @brief Digital I/O modes.
|
||||
*/
|
||||
typedef uint32_t iomode_t;
|
||||
|
||||
/**
|
||||
* @brief Port Identifier.
|
||||
* @details This type can be a scalar or some kind of pointer, do not make
|
||||
* any assumption about it, use the provided macros when populating
|
||||
* variables of this type.
|
||||
*/
|
||||
typedef AT91PS_PIO ioportid_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Identifiers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief PIO port A identifier.
|
||||
*/
|
||||
#define IOPORT1 AT91C_BASE_PIOA
|
||||
|
||||
/**
|
||||
* @brief PIO port B identifier.
|
||||
*/
|
||||
#if (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512) || (SAM7_PLATFORM == SAM7A3) || \
|
||||
defined(__DOXYGEN__)
|
||||
#define IOPORT2 AT91C_BASE_PIOB
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Implementation, some of the following macros could be implemented as */
|
||||
/* functions, if so please put them in pal_lld.c. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level PAL subsystem initialization.
|
||||
*
|
||||
* @param[in] config architecture-dependent ports configuration
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_init(config) _pal_lld_init(config)
|
||||
|
||||
/**
|
||||
* @brief Reads the physical I/O port states.
|
||||
* @details This function is implemented by reading the PIO_PDSR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @return The port bits.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_readport(port) ((port)->PIO_PDSR)
|
||||
|
||||
/**
|
||||
* @brief Reads the output latch.
|
||||
* @details This function is implemented by reading the PIO_ODSR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @return The latched logical states.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_readlatch(port) ((port)->PIO_ODSR)
|
||||
|
||||
/**
|
||||
* @brief Writes a bits mask on a I/O port.
|
||||
* @details This function is implemented by writing the PIO_ODSR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port the port identifier
|
||||
* @param[in] bits the bits to be written on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writeport(port, bits) ((port)->PIO_ODSR = (bits))
|
||||
|
||||
/**
|
||||
* @brief Sets a bits mask on a I/O port.
|
||||
* @details This function is implemented by writing the PIO_SODR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] bits bits to be ORed on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_setport(port, bits) ((port)->PIO_SODR = (bits))
|
||||
|
||||
/**
|
||||
* @brief Clears a bits mask on a I/O port.
|
||||
* @details This function is implemented by writing the PIO_CODR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] bits bits to be cleared on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_clearport(port, bits) ((port)->PIO_CODR = (bits))
|
||||
|
||||
/**
|
||||
* @brief Writes a group of bits.
|
||||
* @details This function is implemented by writing the PIO_OWER, PIO_ODSR and
|
||||
* PIO_OWDR registers, the implementation is not atomic because the
|
||||
* multiple accesses.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] mask group mask
|
||||
* @param[in] offset the group bit offset within the port
|
||||
* @param[in] bits bits to be written. Values exceeding the group
|
||||
* width are masked.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writegroup(port, mask, offset, bits) \
|
||||
((port)->PIO_OWER = (mask) << (offset), \
|
||||
(port)->PIO_ODSR = (bits) << (offset), \
|
||||
(port)->PIO_OWDR = (mask) << (offset))
|
||||
|
||||
/**
|
||||
* @brief Pads group mode setup.
|
||||
* @details This function programs a pads group belonging to the same port
|
||||
* with the specified mode.
|
||||
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
|
||||
* high state.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] mask group mask
|
||||
* @param[in] offset group bit offset within the port
|
||||
* @param[in] mode group mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_setgroupmode(port, mask, offset, mode) \
|
||||
_pal_lld_setgroupmode(port, mask << offset, mode)
|
||||
|
||||
/**
|
||||
* @brief Writes a logical state on an output pad.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
* @param[in] bit logical value, the value must be @p PAL_LOW or
|
||||
* @p PAL_HIGH
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
|
||||
|
||||
extern const PALConfig pal_default_config;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _pal_lld_init(const PALConfig *config);
|
||||
void _pal_lld_setgroupmode(ioportid_t port,
|
||||
ioportmask_t mask,
|
||||
iomode_t mode);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
#endif /* _PAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
136
firmware/chibios/os/hal/platforms/AT91SAM7/platform.dox
Executable file
136
firmware/chibios/os/hal/platforms/AT91SAM7/platform.dox
Executable file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7 AT91SAM7 Drivers
|
||||
* @details This section describes all the supported drivers on the AT91SAM7
|
||||
* platform and the implementation details of the single drivers.
|
||||
*
|
||||
* @ingroup platforms
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_HAL AT91SAM7 Initialization Support
|
||||
* @details The AT91SAM7 HAL support is responsible for system initialization.
|
||||
*
|
||||
* @section at91sam7_hal_1 Supported HW resources
|
||||
* - MC.
|
||||
* - PMC.
|
||||
* .
|
||||
* @section at91sam7_hal_2 AT91SAM7 HAL driver implementation features
|
||||
* - PLLs startup and stabilization.
|
||||
* - Clock source selection.
|
||||
* - Flash wait states.
|
||||
* .
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_MAC AT91SAM7 MAC Support
|
||||
* @details The AT91SAM7 MAC driver supports the EMAC peripheral.
|
||||
*
|
||||
* @section at91sam7_mac_1 Supported HW resources
|
||||
* - EMAC.
|
||||
* .
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_MII AT91SAM7 MII Support
|
||||
* @details This driver supports the AT91SAM7 EMAC peripheral communicating
|
||||
* with an external PHY transceiver. The driver currently supports
|
||||
* the Micrel KS8721 PHY and the Davicom DV9161 modules. This driver
|
||||
* is used internally by the MAC driver.
|
||||
*
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_PAL AT91SAM7 PAL Support
|
||||
* @details The AT91SAM7 PAL driver supports the PIO peripherals.
|
||||
*
|
||||
* @section at91sam7_pal_1 Supported HW resources
|
||||
* - PIOA.
|
||||
* - PIOB.
|
||||
* .
|
||||
* @section at91sam7_pal_2 AT91SAM7 PAL driver implementation features
|
||||
* The PAL driver implementation fully supports the following hardware
|
||||
* capabilities:
|
||||
* - 32 bits wide ports.
|
||||
* - Atomic set/reset functions.
|
||||
* - Output latched regardless of the pad setting.
|
||||
* - Direct read of input pads regardless of the pad setting.
|
||||
* .
|
||||
* @section at91sam7_pal_3 Supported PAL setup modes
|
||||
* The AT91SAM7 PAL driver supports the following I/O modes:
|
||||
* - @p PAL_MODE_RESET.
|
||||
* - @p PAL_MODE_UNCONNECTED.
|
||||
* - @p PAL_MODE_INPUT.
|
||||
* - @p PAL_MODE_INPUT_ANALOG (same as @p PAL_MODE_INPUT).
|
||||
* - @p PAL_MODE_INPUT_PULLUP.
|
||||
* - @p PAL_MODE_OUTPUT_PUSHPULL.
|
||||
* - @p PAL_MODE_OUTPUT_OPENDRAIN.
|
||||
* .
|
||||
* Any attempt to setup an invalid mode is ignored.
|
||||
*
|
||||
* @section at91sam7_pal_4 Suboptimal behavior
|
||||
* The AT91SAM7 PIO is less than optimal in several areas, the limitations
|
||||
* should be taken in account while using the PAL driver:
|
||||
* - Pad/port toggling operations are not atomic.
|
||||
* - Pad/group mode setup is not atomic.
|
||||
* .
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_SERIAL AT91SAM7 Serial Support
|
||||
* @details The AT91SAM7 Serial driver uses the USART/UART peripherals in a
|
||||
* buffered, interrupt driven, implementation.
|
||||
*
|
||||
* @section at91sam7_serial_1 Supported HW resources
|
||||
* The serial driver can support any of the following hardware resources:
|
||||
* - USART1.
|
||||
* - USART2.
|
||||
* - DBGU.
|
||||
* .
|
||||
* @section at91sam7_serial_2 AT91SAM7 Serial driver implementation features
|
||||
* - Clock stop for reduced power usage when the driver is in stop state.
|
||||
* - Each USART can be independently enabled and programmed. Unused
|
||||
* peripherals are left in low power mode.
|
||||
* - Fully interrupt driven.
|
||||
* - Programmable priority levels for each USART.
|
||||
* .
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup AT91SAM7_SPI AT91SAM7 SPI Support
|
||||
* @details The SPI driver supports the AT91SAM7 SPI peripherals using DMA
|
||||
* channels for maximum performance.
|
||||
*
|
||||
* @section at91sam7_spi_1 Supported HW resources
|
||||
* - SPI1.
|
||||
* - SPI2.
|
||||
* .
|
||||
* @section at91sam7_spi_2 AT91SAM7 SPI driver implementation features
|
||||
* - Clock stop for reduced power usage when the driver is in stop state.
|
||||
* - Each SPI can be independently enabled and programmed. Unused
|
||||
* peripherals are left in low power mode.
|
||||
* - Programmable interrupt priority levels for each SPI.
|
||||
* - DMA is used for receiving and transmitting.
|
||||
* .
|
||||
* @ingroup AT91SAM7
|
||||
*/
|
||||
16
firmware/chibios/os/hal/platforms/AT91SAM7/platform.mk
Executable file
16
firmware/chibios/os/hal/platforms/AT91SAM7/platform.mk
Executable file
@@ -0,0 +1,16 @@
|
||||
# List of all the AT91SAM7 platform files.
|
||||
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/AT91SAM7/hal_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/pal_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/i2c_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/adc_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/ext_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/serial_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/spi_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/mac_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/pwm_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/gpt_lld.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/at91sam7_mii.c \
|
||||
${CHIBIOS}/os/hal/platforms/AT91SAM7/at91lib/aic.c
|
||||
|
||||
# Required include directories
|
||||
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/AT91SAM7
|
||||
467
firmware/chibios/os/hal/platforms/AT91SAM7/pwm_lld.c
Executable file
467
firmware/chibios/os/hal/platforms/AT91SAM7/pwm_lld.c
Executable file
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
This file has been contributed by:
|
||||
Andrew Hannam aka inmarket.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/pwm_lld.c
|
||||
* @brief AT91SAM7 PWM Driver subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup PWM
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_PWM || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef UNUSED
|
||||
#elif defined(__GNUC__)
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||
#elif defined(__LCLINT__)
|
||||
# define UNUSED(x) /*@unused@*/ x
|
||||
#else
|
||||
# define UNUSED(x) x
|
||||
#endif
|
||||
|
||||
#define PWMC_M ((AT91S_PWMC *)AT91C_PWMC_MR)
|
||||
|
||||
#define PWM_MCK_MASK 0x0F00
|
||||
#define PWM_MCK_SHIFT 8
|
||||
|
||||
typedef struct pindef {
|
||||
uint32_t portpin; /* Set to 0 if this pin combination is invalid */
|
||||
AT91S_PIO *pio;
|
||||
AT91_REG *perab;
|
||||
} pindef_t;
|
||||
|
||||
typedef struct pwmpindefs {
|
||||
pindef_t pin[3];
|
||||
} pwmpindefs_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD1;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD2;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD3;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD4;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7S64) || (SAM7_PLATFORM == SAM7S128) || \
|
||||
(SAM7_PLATFORM == SAM7S256) || (SAM7_PLATFORM == SAM7S512)
|
||||
|
||||
#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP1 = {{
|
||||
{ AT91C_PA0_PWM0 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
|
||||
{ AT91C_PA11_PWM0, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
{ AT91C_PA23_PWM0, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP2 = {{
|
||||
{ AT91C_PA1_PWM1 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
|
||||
{ AT91C_PA12_PWM1, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
{ AT91C_PA24_PWM1, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP3 = {{
|
||||
{ AT91C_PA2_PWM2 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
|
||||
{ AT91C_PA13_PWM2, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
{ AT91C_PA25_PWM2, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP4 = {{
|
||||
{ AT91C_PA7_PWM3 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
{ AT91C_PA14_PWM3, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
|
||||
{ 0, 0, 0 },
|
||||
}};
|
||||
#endif
|
||||
|
||||
#elif (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512)
|
||||
|
||||
#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP1 = {{
|
||||
{ AT91C_PB19_PWM0, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
|
||||
{ AT91C_PB27_PWM0, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
|
||||
{ 0, 0, 0 },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP2 = {{
|
||||
{ AT91C_PB20_PWM1, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
|
||||
{ AT91C_PB28_PWM1, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
|
||||
{ 0, 0, 0 },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP3 = {{
|
||||
{ AT91C_PB21_PWM2, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
|
||||
{ AT91C_PB29_PWM2, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
|
||||
{ 0, 0, 0 },
|
||||
}};
|
||||
#endif
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
static const pwmpindefs_t PWMP4 = {{
|
||||
{ AT91C_PB22_PWM3, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
|
||||
{ AT91C_PB30_PWM3, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
|
||||
{ 0, 0, 0 },
|
||||
}};
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "PWM pins not defined for this SAM7 version"
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD2;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD3;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
PWMDriver PWMD4;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
/**
|
||||
* @brief Common IRQ handler.
|
||||
*/
|
||||
static void pwm_lld_serve_interrupt(void) {
|
||||
uint32_t isr;
|
||||
|
||||
isr = PWMC_M->PWMC_ISR;
|
||||
#if PWM_USE_PWM1
|
||||
if ((isr & 1) && PWMD1.config->channels[0].callback)
|
||||
PWMD1.config->channels[0].callback(&PWMD1);
|
||||
#endif
|
||||
#if PWM_USE_PWM2
|
||||
if ((isr & 2) && PWMD2.config->channels[0].callback)
|
||||
PWMD2.config->channels[0].callback(&PWMD2);
|
||||
#endif
|
||||
#if PWM_USE_PWM3
|
||||
if ((isr & 4) && PWMD3.config->channels[0].callback)
|
||||
PWMD3.config->channels[0].callback(&PWMD3);
|
||||
#endif
|
||||
#if PWM_USE_PWM4
|
||||
if ((isr & 8) && PWMD4.config->channels[0].callback)
|
||||
PWMD4.config->channels[0].callback(&PWMD4);
|
||||
#endif
|
||||
}
|
||||
|
||||
CH_IRQ_HANDLER(PWMIrqHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
pwm_lld_serve_interrupt();
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level PWM driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_init(void) {
|
||||
|
||||
/* Driver initialization.*/
|
||||
#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
|
||||
pwmObjectInit(&PWMD1);
|
||||
PWMD1.chbit = 1;
|
||||
PWMD1.reg = AT91C_BASE_PWMC_CH0;
|
||||
PWMD1.pins = &PWMP1;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
pwmObjectInit(&PWMD2);
|
||||
PWMD2.chbit = 2;
|
||||
PWMD2.reg = AT91C_BASE_PWMC_CH1;
|
||||
PWMD2.pins = &PWMP2;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
pwmObjectInit(&PWMD3);
|
||||
PWMD3.chbit = 4;
|
||||
PWMD3.reg = AT91C_BASE_PWMC_CH2;
|
||||
PWMD3.pins = &PWMP3;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
pwmObjectInit(&PWMD4);
|
||||
PWMD4.chbit = 8;
|
||||
PWMD4.reg = AT91C_BASE_PWMC_CH3;
|
||||
PWMD4.pins = &PWMP4;
|
||||
#endif
|
||||
|
||||
/* Turn on PWM in the power management controller */
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PWMC);
|
||||
|
||||
/* Setup interrupt handler */
|
||||
PWMC_M->PWMC_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PWMC,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_PWM_PRIORITY,
|
||||
PWMIrqHandler);
|
||||
AIC_EnableIT(AT91C_ID_PWMC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the PWM peripheral.
|
||||
*
|
||||
* @param[in] pwmp pointer to the @p PWMDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_start(PWMDriver *pwmp) {
|
||||
uint32_t mode, mr, div, pre;
|
||||
|
||||
/* Steps:
|
||||
1. Turn the IO pin to a PWM output
|
||||
2. Configuration of Clock if DIVA or DIVB used
|
||||
3. Selection of the clock for each channel (CPRE field in the PWM_CMRx register)
|
||||
4. Configuration of the waveform alignment for each channel (CALG field in the PWM_CMRx register)
|
||||
5. Configuration of the output waveform polarity for each channel (CPOL in the PWM_CMRx register)
|
||||
6. Configuration of the period for each channel (CPRD in the PWM_CPRDx register). Writing in
|
||||
PWM_CPRDx Register is possible while the channel is disabled. After validation of the
|
||||
channel, the user must use PWM_CUPDx Register to update PWM_CPRDx
|
||||
7. Enable Interrupts (Writing CHIDx in the PWM_IER register)
|
||||
*/
|
||||
|
||||
/* Make sure it is off first */
|
||||
pwm_lld_disable_channel(pwmp, 0);
|
||||
|
||||
/* Configuration.*/
|
||||
mode = pwmp->config->channels[0].mode;
|
||||
|
||||
/* Step 1 */
|
||||
if (mode & PWM_OUTPUT_PIN1) {
|
||||
pwmp->pins->pin[0].perab[0] = pwmp->pins->pin[0].portpin; /* Select A or B peripheral */
|
||||
pwmp->pins->pin[0].pio->PIO_PDR = pwmp->pins->pin[0].portpin; /* Turn PIO into PWM output */
|
||||
pwmp->pins->pin[0].pio->PIO_MDDR = pwmp->pins->pin[0].portpin; /* Turn off PIO multi-drive */
|
||||
if (mode & PWM_DISABLEPULLUP_PIN1)
|
||||
pwmp->pins->pin[0].pio->PIO_PPUDR = pwmp->pins->pin[0].portpin; /* Turn off PIO pullup */
|
||||
else
|
||||
pwmp->pins->pin[0].pio->PIO_PPUER = pwmp->pins->pin[0].portpin; /* Turn on PIO pullup */
|
||||
}
|
||||
if (mode & PWM_OUTPUT_PIN2) {
|
||||
pwmp->pins->pin[1].perab[0] = pwmp->pins->pin[1].portpin;
|
||||
pwmp->pins->pin[1].pio->PIO_PDR = pwmp->pins->pin[1].portpin;
|
||||
pwmp->pins->pin[1].pio->PIO_MDDR = pwmp->pins->pin[1].portpin;
|
||||
if (mode & PWM_DISABLEPULLUP_PIN2)
|
||||
pwmp->pins->pin[1].pio->PIO_PPUDR = pwmp->pins->pin[1].portpin;
|
||||
else
|
||||
pwmp->pins->pin[1].pio->PIO_PPUER = pwmp->pins->pin[1].portpin;
|
||||
}
|
||||
if ((mode & PWM_OUTPUT_PIN3) && pwmp->pins->pin[2].portpin) {
|
||||
pwmp->pins->pin[2].perab[0] = pwmp->pins->pin[2].portpin;
|
||||
pwmp->pins->pin[2].pio->PIO_PDR = pwmp->pins->pin[2].portpin;
|
||||
pwmp->pins->pin[2].pio->PIO_MDDR = pwmp->pins->pin[2].portpin;
|
||||
if (mode & PWM_DISABLEPULLUP_PIN3)
|
||||
pwmp->pins->pin[2].pio->PIO_PPUDR = pwmp->pins->pin[2].portpin;
|
||||
else
|
||||
pwmp->pins->pin[2].pio->PIO_PPUER = pwmp->pins->pin[2].portpin;
|
||||
}
|
||||
|
||||
/* Step 2 */
|
||||
if ((mode & PWM_MCK_MASK) == PWM_MCK_DIV_CLKA) {
|
||||
if (!pwmp->config->frequency) {
|
||||
/* As slow as we go */
|
||||
PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0xFFFF0000) | (10 << 8) | (255 << 0);
|
||||
} else if (pwmp->config->frequency > MCK) {
|
||||
/* Just use MCLK */
|
||||
mode &= ~PWM_MCK_MASK;
|
||||
} else {
|
||||
div = MCK / pwmp->config->frequency;
|
||||
if (mode & PWM_OUTPUT_CENTER) div >>= 1;
|
||||
for(pre = 0; div > 255 && pre < 10; pre++) div >>= 1;
|
||||
if (div > 255) div = 255;
|
||||
PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0xFFFF0000) | (pre << 8) | (div << 0);
|
||||
}
|
||||
} else if ((mode & PWM_MCK_MASK) == PWM_MCK_DIV_CLKB) {
|
||||
if (!pwmp->config->frequency) {
|
||||
/* As slow as we go */
|
||||
PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0x0000FFFF) | (10 << 24) | (255 << 16);
|
||||
} else if (pwmp->config->frequency > MCK) {
|
||||
/* Just use MCLK */
|
||||
mode &= ~PWM_MCK_MASK;
|
||||
} else {
|
||||
div = MCK / pwmp->config->frequency;
|
||||
if (mode & PWM_OUTPUT_CENTER) div >>= 1;
|
||||
for(pre = 0; div > 255 && pre < 10; pre++) div >>= 1;
|
||||
if (div > 255) div = 255;
|
||||
PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0x0000FFFF) | (pre << 24) | (div << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 3 -> 5 */
|
||||
mr = (mode & PWM_MCK_MASK) >> PWM_MCK_SHIFT;
|
||||
if (mode & PWM_OUTPUT_CENTER) mr |= AT91C_PWMC_CALG;
|
||||
if (mode & PWM_OUTPUT_ACTIVE_HIGH) mr |= AT91C_PWMC_CPOL;
|
||||
pwmp->reg->PWMC_CMR = mr;
|
||||
|
||||
/* Step 6 */
|
||||
pwmp->reg->PWMC_CPRDR = pwmp->period;
|
||||
|
||||
/* Step 7 */
|
||||
if (pwmp->config->channels[0].callback)
|
||||
PWMC_M->PWMC_IER = pwmp->chbit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the PWM peripheral.
|
||||
*
|
||||
* @param[in] pwmp pointer to the @p PWMDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_stop(PWMDriver *pwmp) {
|
||||
/* Make sure it is off */
|
||||
pwm_lld_disable_channel(pwmp, 0);
|
||||
|
||||
/* Turn the pin back to a PIO pin - we have forgotten pull-up and multi-drive state for the pin though */
|
||||
if (pwmp->config->channels[0].mode & PWM_OUTPUT_PIN1)
|
||||
pwmp->pins->pin[0].pio->PIO_PER = pwmp->pins->pin[0].portpin;
|
||||
if (pwmp->config->channels[0].mode & PWM_OUTPUT_PIN2)
|
||||
pwmp->pins->pin[1].pio->PIO_PER = pwmp->pins->pin[1].portpin;
|
||||
if ((pwmp->config->channels[0].mode & PWM_OUTPUT_PIN3) && pwmp->pins->pin[2].portpin)
|
||||
pwmp->pins->pin[2].pio->PIO_PER = pwmp->pins->pin[2].portpin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the period the PWM peripheral.
|
||||
* @details This function changes the period of a PWM unit that has already
|
||||
* been activated using @p pwmStart().
|
||||
* @pre The PWM unit must have been activated using @p pwmStart().
|
||||
* @post The PWM unit period is changed to the new value.
|
||||
* @note The function has effect at the next cycle start.
|
||||
* @note If a period is specified that is shorter than the pulse width
|
||||
* programmed in one of the channels then the behavior is not
|
||||
* guaranteed.
|
||||
*
|
||||
* @param[in] pwmp pointer to a @p PWMDriver object
|
||||
* @param[in] period new cycle time in ticks
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period) {
|
||||
pwmp->period = period;
|
||||
|
||||
if (PWMC_M->PWMC_SR & pwmp->chbit) {
|
||||
pwmp->reg->PWMC_CMR |= AT91C_PWMC_CPD;
|
||||
pwmp->reg->PWMC_CUPDR = period;
|
||||
} else {
|
||||
pwmp->reg->PWMC_CPRDR = period;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a PWM channel.
|
||||
* @pre The PWM unit must have been activated using @p pwmStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] pwmp pointer to a @p PWMDriver object
|
||||
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
|
||||
* @param[in] width PWM pulse width as clock pulses number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_enable_channel(PWMDriver *pwmp,
|
||||
pwmchannel_t UNUSED(channel),
|
||||
pwmcnt_t width) {
|
||||
/*
|
||||
6. Configuration of the duty cycle for each channel (CDTY in the PWM_CDTYx register).
|
||||
Writing in PWM_CDTYx Register is possible while the channel is disabled. After validation of
|
||||
the channel, the user must use PWM_CUPDx Register to update PWM_CDTYx.
|
||||
7. Enable the PWM channel (Writing CHIDx in the PWM_ENA register)
|
||||
*/
|
||||
|
||||
/* Step 6 */
|
||||
if (PWMC_M->PWMC_SR & pwmp->chbit) {
|
||||
pwmp->reg->PWMC_CMR &= ~AT91C_PWMC_CPD;
|
||||
pwmp->reg->PWMC_CUPDR = width;
|
||||
} else {
|
||||
pwmp->reg->PWMC_CDTYR = width;
|
||||
PWMC_M->PWMC_ENA = pwmp->chbit;
|
||||
}
|
||||
|
||||
/* Step 7 */
|
||||
PWMC_M->PWMC_ENA = pwmp->chbit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a PWM channel.
|
||||
* @pre The PWM unit must have been activated using @p pwmStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] pwmp pointer to a @p PWMDriver object
|
||||
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t UNUSED(channel)) {
|
||||
PWMC_M->PWMC_IDR = pwmp->chbit;
|
||||
PWMC_M->PWMC_DIS = pwmp->chbit;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_PWM */
|
||||
|
||||
/** @} */
|
||||
284
firmware/chibios/os/hal/platforms/AT91SAM7/pwm_lld.h
Executable file
284
firmware/chibios/os/hal/platforms/AT91SAM7/pwm_lld.h
Executable file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
This file has been contributed by:
|
||||
Andrew Hannam aka inmarket.
|
||||
*/
|
||||
/**
|
||||
* @file AT91SAM7/pwm_lld.h
|
||||
* @brief AT91SAM7 PWM Driver subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup PWM
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _PWM_LLD_H_
|
||||
#define _PWM_LLD_H_
|
||||
|
||||
#if HAL_USE_PWM || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of PWM channels per PWM driver.
|
||||
*/
|
||||
#define PWM_CHANNELS 1
|
||||
|
||||
/**
|
||||
* @brief PWM device interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(AT91SAM7_PWM_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define AT91SAM7_PWM_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 4)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWMD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for PWMD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(PWM_USE_PWM1) || defined(__DOXYGEN__)
|
||||
#define PWM_USE_PWM1 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWMD2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for PWMD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(PWM_USE_PWM2) || defined(__DOXYGEN__)
|
||||
#define PWM_USE_PWM2 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWMD3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for PWMD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(PWM_USE_PWM3) || defined(__DOXYGEN__)
|
||||
#define PWM_USE_PWM3 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWMD4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for PWMD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(PWM_USE_PWM4) || defined(__DOXYGEN__)
|
||||
#define PWM_USE_PWM4 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWM left (count up) logic
|
||||
*/
|
||||
#define PWM_OUTPUT_LEFT 0x00000000
|
||||
|
||||
/**
|
||||
* @brief PWM center (count up-down) logic. Gives symetric waveform
|
||||
*/
|
||||
#define PWM_OUTPUT_CENTER 0x00000010
|
||||
|
||||
/**
|
||||
* @brief PWM Master Clock = MCK / 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, CLKA or CLKB. CLKA or CLKB uses the frequency field
|
||||
*/
|
||||
#define PWM_MCK_DIV_1 0x00000000
|
||||
#define PWM_MCK_DIV_2 0x00000100
|
||||
#define PWM_MCK_DIV_4 0x00000200
|
||||
#define PWM_MCK_DIV_8 0x00000300
|
||||
#define PWM_MCK_DIV_16 0x00000400
|
||||
#define PWM_MCK_DIV_32 0x00000500
|
||||
#define PWM_MCK_DIV_64 0x00000600
|
||||
#define PWM_MCK_DIV_128 0x00000700
|
||||
#define PWM_MCK_DIV_256 0x00000800
|
||||
#define PWM_MCK_DIV_512 0x00000900
|
||||
#define PWM_MCK_DIV_1024 0x00000A00
|
||||
#define PWM_MCK_DIV_CLKA 0x00000B00
|
||||
#define PWM_MCK_DIV_CLKB 0x00000C00
|
||||
|
||||
/**
|
||||
* @brief Which PWM output pins to turn on. PIN1 is the lowest numbered pin, PIN2 next lowest, and then on some packages PIN3.
|
||||
*/
|
||||
#define PWM_OUTPUT_PIN1 0x00001000
|
||||
#define PWM_OUTPUT_PIN2 0x00002000
|
||||
#define PWM_OUTPUT_PIN3 0x00004000
|
||||
|
||||
/**
|
||||
* @brief Which PWM output pins should have pullups disabled.
|
||||
*/
|
||||
#define PWM_DISABLEPULLUP_PIN1 0x00010000
|
||||
#define PWM_DISABLEPULLUP_PIN2 0x00020000
|
||||
#define PWM_DISABLEPULLUP_PIN3 0x00040000
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief PWM mode type.
|
||||
*/
|
||||
typedef uint32_t pwmmode_t;
|
||||
|
||||
/**
|
||||
* @brief PWM channel type.
|
||||
*/
|
||||
typedef uint8_t pwmchannel_t;
|
||||
|
||||
/**
|
||||
* @brief PWM counter type.
|
||||
*/
|
||||
typedef uint16_t pwmcnt_t;
|
||||
|
||||
/**
|
||||
* @brief PWM driver channel configuration structure.
|
||||
* @note Some architectures may not be able to support the channel mode
|
||||
* or the callback, in this case the fields are ignored.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channel active logic level.
|
||||
*/
|
||||
pwmmode_t mode;
|
||||
/**
|
||||
* @brief Channel callback pointer.
|
||||
* @note This callback is invoked on the channel compare event. If set to
|
||||
* @p NULL then the callback is disabled.
|
||||
*/
|
||||
pwmcallback_t callback;
|
||||
/* End of the mandatory fields.*/
|
||||
} PWMChannelConfig;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note Implementations may extend this structure to contain more,
|
||||
* architecture dependent, fields.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Timer clock in Hz.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* frequency specifications.
|
||||
*/
|
||||
uint32_t frequency;
|
||||
/**
|
||||
* @brief PWM period in ticks.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* period specifications.
|
||||
*/
|
||||
pwmcnt_t period;
|
||||
/**
|
||||
* @brief Periodic callback pointer.
|
||||
* @note This callback is invoked on PWM counter reset. If set to
|
||||
* @p NULL then the callback is disabled.
|
||||
*/
|
||||
pwmcallback_t callback;
|
||||
/**
|
||||
* @brief Channels configurations.
|
||||
*/
|
||||
PWMChannelConfig channels[PWM_CHANNELS];
|
||||
/* End of the mandatory fields.*/
|
||||
} PWMConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an PWM driver.
|
||||
* @note Implementations may extend this structure to contain more,
|
||||
* architecture dependent, fields.
|
||||
*/
|
||||
struct PWMDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
pwmstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const PWMConfig *config;
|
||||
/**
|
||||
* @brief Current PWM period in ticks.
|
||||
*/
|
||||
pwmcnt_t period;
|
||||
#if defined(PWM_DRIVER_EXT_FIELDS)
|
||||
PWM_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
|
||||
/* End of the mandatory fields.*/
|
||||
|
||||
/**
|
||||
* @brief The PWM internal channel number as a bit mask (1, 2, 4 or 8).
|
||||
*/
|
||||
uint32_t chbit;
|
||||
/**
|
||||
* @brief Pointer to the PWMCx registers block.
|
||||
*/
|
||||
AT91S_PWMC_CH *reg;
|
||||
/**
|
||||
* @brief Pointer to the output pins descriptor.
|
||||
*/
|
||||
const struct pwmpindefs *pins;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
|
||||
extern PWMDriver PWMD1;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
|
||||
extern PWMDriver PWMD2;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
|
||||
extern PWMDriver PWMD3;
|
||||
#endif
|
||||
|
||||
#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
|
||||
extern PWMDriver PWMD4;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void pwm_lld_init(void);
|
||||
void pwm_lld_start(PWMDriver *pwmp);
|
||||
void pwm_lld_stop(PWMDriver *pwmp);
|
||||
void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period);
|
||||
void pwm_lld_enable_channel(PWMDriver *pwmp,
|
||||
pwmchannel_t channel,
|
||||
pwmcnt_t width);
|
||||
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_PWM */
|
||||
|
||||
#endif /* _PWM_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
444
firmware/chibios/os/hal/platforms/AT91SAM7/serial_lld.c
Executable file
444
firmware/chibios/os/hal/platforms/AT91SAM7/serial_lld.c
Executable file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/serial_lld.c
|
||||
* @brief AT91SAM7 low level serial driver code.
|
||||
*
|
||||
* @addtogroup SERIAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7S64) || (SAM7_PLATFORM == SAM7S128) || \
|
||||
(SAM7_PLATFORM == SAM7S256) || (SAM7_PLATFORM == SAM7S512)
|
||||
|
||||
#define SAM7_USART0_RX AT91C_PA5_RXD0
|
||||
#define SAM7_USART0_TX AT91C_PA6_TXD0
|
||||
#define SAM7_USART1_RX AT91C_PA21_RXD1
|
||||
#define SAM7_USART1_TX AT91C_PA22_TXD1
|
||||
#define SAM7_DBGU_RX AT91C_PA9_DRXD
|
||||
#define SAM7_DBGU_TX AT91C_PA10_DTXD
|
||||
|
||||
#elif (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
|
||||
(SAM7_PLATFORM == SAM7X512)
|
||||
|
||||
#define SAM7_USART0_RX AT91C_PA0_RXD0
|
||||
#define SAM7_USART0_TX AT91C_PA1_TXD0
|
||||
#define SAM7_USART1_RX AT91C_PA5_RXD1
|
||||
#define SAM7_USART1_TX AT91C_PA6_TXD1
|
||||
#define SAM7_DBGU_RX AT91C_PA27_DRXD
|
||||
#define SAM7_DBGU_TX AT91C_PA28_DTXD
|
||||
|
||||
#elif (SAM7_PLATFORM == SAM7A3)
|
||||
#define SAM7_USART0_RX AT91C_PA2_RXD0
|
||||
#define SAM7_USART0_TX AT91C_PA3_TXD0
|
||||
#define SAM7_USART1_RX AT91C_PA7_RXD1
|
||||
#define SAM7_USART1_TX AT91C_PA8_TXD1
|
||||
#define SAM7_USART2_RX AT91C_PA9_RXD2
|
||||
#define SAM7_USART2_TX AT91C_PA10_TXD2
|
||||
#define SAM7_DBGU_RX AT91C_PA30_DRXD
|
||||
#define SAM7_DBGU_TX AT91C_PA31_DTXD
|
||||
|
||||
#else
|
||||
#error "serial lines not defined for this SAM7 version"
|
||||
#endif /* HAL_USE_SERIAL */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if USE_SAM7_USART0 || defined(__DOXYGEN__)
|
||||
/** @brief USART0 serial driver identifier.*/
|
||||
SerialDriver SD1;
|
||||
#endif
|
||||
|
||||
#if USE_SAM7_USART1 || defined(__DOXYGEN__)
|
||||
/** @brief USART1 serial driver identifier.*/
|
||||
SerialDriver SD2;
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2 || defined(__DOXYGEN__)
|
||||
/** @brief USART2 serial driver identifier.*/
|
||||
SerialDriver SD3;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USE_SAM7_DBGU_UART || defined(__DOXYGEN__)
|
||||
/** @brief DBGU_UART serial driver identifier.*/
|
||||
SerialDriver SDDBG;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @brief Driver default configuration.*/
|
||||
static const SerialConfig default_config = {
|
||||
SERIAL_DEFAULT_BITRATE,
|
||||
AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK |
|
||||
AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief USART initialization.
|
||||
*
|
||||
* @param[in] sdp communication channel associated to the USART
|
||||
* @param[in] config the architecture-dependent serial driver configuration
|
||||
*/
|
||||
static void usart_init(SerialDriver *sdp, const SerialConfig *config) {
|
||||
AT91PS_USART u = sdp->usart;
|
||||
|
||||
/* Disables IRQ sources and stop operations.*/
|
||||
u->US_IDR = 0xFFFFFFFF;
|
||||
u->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
|
||||
|
||||
/* New parameters setup.*/
|
||||
if (config->sc_mr & AT91C_US_OVER)
|
||||
u->US_BRGR = MCK / (config->sc_speed * 8);
|
||||
else
|
||||
u->US_BRGR = MCK / (config->sc_speed * 16);
|
||||
u->US_MR = config->sc_mr;
|
||||
u->US_RTOR = 0;
|
||||
u->US_TTGR = 0;
|
||||
|
||||
/* Enables operations and IRQ sources.*/
|
||||
u->US_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_DTREN | AT91C_US_RTSEN;
|
||||
u->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE |
|
||||
AT91C_US_RXBRK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART de-initialization.
|
||||
*
|
||||
* @param[in] u pointer to an USART I/O block
|
||||
*/
|
||||
static void usart_deinit(AT91PS_USART u) {
|
||||
|
||||
/* Disables IRQ sources and stop operations.*/
|
||||
u->US_IDR = 0xFFFFFFFF;
|
||||
u->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
|
||||
u->US_MR = 0;
|
||||
u->US_RTOR = 0;
|
||||
u->US_TTGR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Error handling routine.
|
||||
*
|
||||
* @param[in] err USART CSR register value
|
||||
* @param[in] sdp communication channel associated to the USART
|
||||
*/
|
||||
static void set_error(SerialDriver *sdp, AT91_REG csr) {
|
||||
flagsmask_t sts = 0;
|
||||
|
||||
if (csr & AT91C_US_OVRE)
|
||||
sts |= SD_OVERRUN_ERROR;
|
||||
if (csr & AT91C_US_PARE)
|
||||
sts |= SD_PARITY_ERROR;
|
||||
if (csr & AT91C_US_FRAME)
|
||||
sts |= SD_FRAMING_ERROR;
|
||||
if (csr & AT91C_US_RXBRK)
|
||||
sts |= SD_BREAK_DETECTED;
|
||||
chSysLockFromIsr();
|
||||
chnAddFlagsI(sdp, sts);
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
#if !USE_SAM7_DBGU_UART
|
||||
static
|
||||
#endif
|
||||
/**
|
||||
* @brief Common IRQ handler.
|
||||
*
|
||||
* @param[in] sdp communication channel associated to the USART
|
||||
*/
|
||||
void sd_lld_serve_interrupt(SerialDriver *sdp) {
|
||||
uint32_t csr;
|
||||
AT91PS_USART u = sdp->usart;
|
||||
|
||||
csr = u->US_CSR;
|
||||
if (csr & AT91C_US_RXRDY) {
|
||||
chSysLockFromIsr();
|
||||
sdIncomingDataI(sdp, u->US_RHR);
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
if ((u->US_IMR & AT91C_US_TXRDY) && (csr & AT91C_US_TXRDY)) {
|
||||
msg_t b;
|
||||
|
||||
chSysLockFromIsr();
|
||||
b = chOQGetI(&sdp->oqueue);
|
||||
if (b < Q_OK) {
|
||||
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
|
||||
u->US_IDR = AT91C_US_TXRDY;
|
||||
}
|
||||
else
|
||||
u->US_THR = b;
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
csr &= (AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK);
|
||||
if (csr != 0) {
|
||||
set_error(sdp, csr);
|
||||
u->US_CR = AT91C_US_RSTSTA;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
#if USE_SAM7_USART0 || defined(__DOXYGEN__)
|
||||
static void notify1(GenericQueue *qp) {
|
||||
|
||||
(void)qp;
|
||||
AT91C_BASE_US0->US_IER = AT91C_US_TXRDY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_SAM7_USART1 || defined(__DOXYGEN__)
|
||||
static void notify2(GenericQueue *qp) {
|
||||
|
||||
(void)qp;
|
||||
AT91C_BASE_US1->US_IER = AT91C_US_TXRDY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2 || defined(__DOXYGEN__)
|
||||
static void notify3(GenericQueue *qp) {
|
||||
|
||||
(void)qp;
|
||||
AT91C_BASE_US2->US_IER = AT91C_US_TXRDY;
|
||||
}
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
|
||||
#if USE_SAM7_DBGU_UART || defined(__DOXYGEN__)
|
||||
static void notify_dbg(GenericQueue *qp) {
|
||||
|
||||
(void)qp;
|
||||
AT91C_BASE_DBGU->DBGU_IER = AT91C_US_TXRDY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if USE_SAM7_USART0 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief USART0 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(USART0IrqHandler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
sd_lld_serve_interrupt(&SD1);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_SAM7_USART1 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief USART1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(USART1IrqHandler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
sd_lld_serve_interrupt(&SD2);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief USART2 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
CH_IRQ_HANDLER(USART2IrqHandler) {
|
||||
|
||||
CH_IRQ_PROLOGUE();
|
||||
sd_lld_serve_interrupt(&SD3);
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
|
||||
/* note - DBGU_UART IRQ is the SysIrq in board.c
|
||||
since it's not vectored separately by the AIC.*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level serial driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sd_lld_init(void) {
|
||||
|
||||
#if USE_SAM7_USART0
|
||||
sdObjectInit(&SD1, NULL, notify1);
|
||||
SD1.usart = AT91C_BASE_US0;
|
||||
AT91C_BASE_PIOA->PIO_PDR = SAM7_USART0_RX | SAM7_USART0_TX;
|
||||
AT91C_BASE_PIOA->PIO_ASR = SAM7_USART0_RX | SAM7_USART0_TX;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = SAM7_USART0_RX | SAM7_USART0_TX;
|
||||
AIC_ConfigureIT(AT91C_ID_US0,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | SAM7_USART0_PRIORITY,
|
||||
USART0IrqHandler);
|
||||
#endif
|
||||
|
||||
#if USE_SAM7_USART1
|
||||
sdObjectInit(&SD2, NULL, notify2);
|
||||
SD2.usart = AT91C_BASE_US1;
|
||||
AT91C_BASE_PIOA->PIO_PDR = SAM7_USART1_RX | SAM7_USART1_TX;
|
||||
AT91C_BASE_PIOA->PIO_ASR = SAM7_USART1_RX | SAM7_USART1_TX;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = SAM7_USART1_RX | SAM7_USART1_TX;
|
||||
AIC_ConfigureIT(AT91C_ID_US1,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | SAM7_USART1_PRIORITY,
|
||||
USART1IrqHandler);
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2
|
||||
sdObjectInit(&SD3, NULL, notify3);
|
||||
SD3.usart = AT91C_BASE_US2;
|
||||
AT91C_BASE_PIOA->PIO_PDR = SAM7_USART2_RX | SAM7_USART2_TX;
|
||||
AT91C_BASE_PIOA->PIO_ASR = SAM7_USART2_RX | SAM7_USART2_TX;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = SAM7_USART2_RX | SAM7_USART2_TX;
|
||||
AIC_ConfigureIT(AT91C_ID_US2,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | SAM7_USART2_PRIORITY,
|
||||
USART2IrqHandler);
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
|
||||
#if USE_SAM7_DBGU_UART
|
||||
sdObjectInit(&SDDBG, NULL, notify_dbg);
|
||||
/* 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.*/
|
||||
SDDBG.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;
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = SAM7_DBGU_RX | SAM7_DBGU_TX;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low level serial driver configuration and (re)start.
|
||||
*
|
||||
* @param[in] sdp pointer to a @p SerialDriver object
|
||||
* @param[in] config the architecture-dependent serial driver configuration.
|
||||
* If this parameter is set to @p NULL then a default
|
||||
* configuration is used.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
|
||||
|
||||
if (config == NULL)
|
||||
config = &default_config;
|
||||
|
||||
if (sdp->state == SD_STOP) {
|
||||
#if USE_SAM7_USART0
|
||||
if (&SD1 == sdp) {
|
||||
/* Starts the clock and clears possible sources of immediate interrupts.*/
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US0);
|
||||
/* Enables associated interrupt vector.*/
|
||||
AIC_EnableIT(AT91C_ID_US0);
|
||||
}
|
||||
#endif
|
||||
#if USE_SAM7_USART1
|
||||
if (&SD2 == sdp) {
|
||||
/* Starts the clock and clears possible sources of immediate interrupts.*/
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US1);
|
||||
/* Enables associated interrupt vector.*/
|
||||
AIC_EnableIT(AT91C_ID_US1);
|
||||
}
|
||||
#endif
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2
|
||||
if (&SD3 == sdp) {
|
||||
/* Starts the clock and clears possible sources of immediate interrupts.*/
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US2);
|
||||
/* Enables associated interrupt vector.*/
|
||||
AIC_EnableIT(AT91C_ID_US2);
|
||||
}
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
/* Note - no explicit start for SD3 (DBGU_UART) since it's not included
|
||||
in the AIC or PMC.*/
|
||||
}
|
||||
usart_init(sdp, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low level serial driver stop.
|
||||
* @details De-initializes the USART, stops the associated clock, resets the
|
||||
* interrupt vector.
|
||||
*
|
||||
* @param[in] sdp pointer to a @p SerialDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sd_lld_stop(SerialDriver *sdp) {
|
||||
|
||||
if (sdp->state == SD_READY) {
|
||||
usart_deinit(sdp->usart);
|
||||
#if USE_SAM7_USART0
|
||||
if (&SD1 == sdp) {
|
||||
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_US0);
|
||||
AIC_DisableIT(AT91C_ID_US0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if USE_SAM7_USART1
|
||||
if (&SD2 == sdp) {
|
||||
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_US1);
|
||||
AIC_DisableIT(AT91C_ID_US1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if USE_SAM7_DBGU_UART
|
||||
if (&SDDBG == sdp) {
|
||||
AT91C_BASE_DBGU->DBGU_IDR = 0xFFFFFFFF;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_SERIAL */
|
||||
|
||||
/** @} */
|
||||
191
firmware/chibios/os/hal/platforms/AT91SAM7/serial_lld.h
Executable file
191
firmware/chibios/os/hal/platforms/AT91SAM7/serial_lld.h
Executable file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/serial_lld.h
|
||||
* @brief AT91SAM7 low level serial driver header.
|
||||
*
|
||||
* @addtogroup SERIAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _SERIAL_LLD_H_
|
||||
#define _SERIAL_LLD_H_
|
||||
|
||||
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief UART0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for USART1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(USE_SAM7_USART0) || defined(__DOXYGEN__)
|
||||
#define USE_SAM7_USART0 TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for USART2 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(USE_SAM7_USART1) || defined(__DOXYGEN__)
|
||||
#define USE_SAM7_USART1 TRUE
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
/**
|
||||
* @brief UART2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for USART3 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(USE_SAM7_USART2) || defined(__DOXYGEN__)
|
||||
#define USE_SAM7_USART2 TRUE
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
|
||||
/**
|
||||
* @brief DBGU UART driver enable switch.
|
||||
* @details If set to @p TRUE the support for the DBGU UART is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(USE_SAM7_DBGU_UART) || defined(__DOXYGEN__)
|
||||
#define USE_SAM7_DBGU_UART TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAM7_USART0_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAM7_USART0_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAM7_USART1_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAM7_USART1_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
/**
|
||||
* @brief UART2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAM7_USART2_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAM7_USART2_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
#endif /* (SAM7_PLATFORM == SAM7A3) */
|
||||
|
||||
/**
|
||||
* @brief DBGU_UART interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAM7_DBGU_UART_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAM7_DBGU_UART_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2)
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief AT91SAM7 Serial Driver configuration structure.
|
||||
* @details An instance of this structure must be passed to @p sdStart()
|
||||
* in order to configure and start a serial driver operations.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Bit rate.
|
||||
* @details This is written to the US_BRGR register of the appropriate AT91S_USART
|
||||
*/
|
||||
uint32_t sc_speed;
|
||||
/**
|
||||
* @brief Initialization value for the MR register.
|
||||
* @details This is written to the US_MR register of the appropriate AT91S_USART
|
||||
*/
|
||||
uint32_t sc_mr;
|
||||
} SerialConfig;
|
||||
|
||||
/**
|
||||
* @brief @p SerialDriver specific data.
|
||||
*/
|
||||
#define _serial_driver_data \
|
||||
_base_asynchronous_channel_data \
|
||||
/* Driver state.*/ \
|
||||
sdstate_t state; \
|
||||
/* Input queue.*/ \
|
||||
InputQueue iqueue; \
|
||||
/* Output queue.*/ \
|
||||
OutputQueue oqueue; \
|
||||
/* Input circular buffer.*/ \
|
||||
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
|
||||
/* Output circular buffer.*/ \
|
||||
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
|
||||
/* End of the mandatory fields.*/ \
|
||||
/* Pointer to the USART registers block.*/ \
|
||||
AT91PS_USART usart;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if USE_SAM7_USART0 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD1;
|
||||
#endif
|
||||
#if USE_SAM7_USART1 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD2;
|
||||
#endif
|
||||
#if (SAM7_PLATFORM == SAM7A3)
|
||||
#if USE_SAM7_USART2 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD3;
|
||||
#endif
|
||||
#endif
|
||||
#if USE_SAM7_DBGU_UART
|
||||
extern SerialDriver SDDBG;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void sd_lld_init(void);
|
||||
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
|
||||
void sd_lld_stop(SerialDriver *sdp);
|
||||
#if USE_SAM7_DBGU_UART
|
||||
void sd_lld_serve_interrupt(SerialDriver *sdp);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_SERIAL */
|
||||
|
||||
#endif /* _SERIAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
436
firmware/chibios/os/hal/platforms/AT91SAM7/spi_lld.c
Executable file
436
firmware/chibios/os/hal/platforms/AT91SAM7/spi_lld.c
Executable file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/spi_lld.c
|
||||
* @brief AT91SAM7 low level SPI driver code.
|
||||
*
|
||||
* @addtogroup SPI
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_SPI || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#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
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Idle line value.
|
||||
* @details This thing's DMA apparently does not allow to *not* increment
|
||||
* the memory pointer so a buffer filled with ones is required
|
||||
* somewhere.
|
||||
* @note This buffer size also limits the maximum transfer size, 512B,
|
||||
* for @p spiReceive() and @p spiIgnore(). @p spiSend() and
|
||||
* @p spiExchange are not affected.
|
||||
*/
|
||||
static const uint16_t idle_buf[] = {
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes a SPI device.
|
||||
*/
|
||||
static void spi_init(AT91PS_SPI spi) {
|
||||
|
||||
/* Software reset must be written twice (errata for revision B parts).*/
|
||||
spi->SPI_CR = AT91C_SPI_SWRST;
|
||||
spi->SPI_CR = AT91C_SPI_SWRST;
|
||||
spi->SPI_RCR = 0;
|
||||
spi->SPI_RNCR = 0;
|
||||
spi->SPI_TCR = 0;
|
||||
spi->SPI_TNCR = 0;
|
||||
spi->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
|
||||
spi->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
/**
|
||||
* @brief Shared interrupt handling code.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*/
|
||||
static void spi_lld_serve_interrupt(SPIDriver *spip) {
|
||||
uint32_t sr = spip->spi->SPI_SR;
|
||||
|
||||
if ((sr & AT91C_SPI_ENDRX) != 0) {
|
||||
(void)spip->spi->SPI_RDR; /* Clears eventual overflow.*/
|
||||
spip->spi->SPI_PTCR = AT91C_PDC_RXTDIS |
|
||||
AT91C_PDC_TXTDIS; /* PDC disabled. */
|
||||
spip->spi->SPI_IDR = AT91C_SPI_ENDRX; /* Interrupt disabled. */
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIDIS; /* SPI disabled. */
|
||||
/* Portable SPI ISR code defined in the high level driver, note, it is
|
||||
a macro.*/
|
||||
_spi_isr_code(spip);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* 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. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level SPI driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_init(void) {
|
||||
|
||||
#if AT91SAM7_SPI_USE_SPI0
|
||||
spiObjectInit(&SPID1);
|
||||
SPID1.spi = AT91C_BASE_SPI0;
|
||||
spi_init(AT91C_BASE_SPI0);
|
||||
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;
|
||||
AIC_ConfigureIT(AT91C_ID_SPI0,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_SPI0_PRIORITY,
|
||||
SPI0IrqHandler);
|
||||
#endif
|
||||
|
||||
#if AT91SAM7_SPI_USE_SPI1
|
||||
spiObjectInit(&SPID2);
|
||||
SPID2.spi = AT91C_BASE_SPI1;
|
||||
spi_init(AT91C_BASE_SPI1);
|
||||
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;
|
||||
AIC_ConfigureIT(AT91C_ID_SPI1,
|
||||
AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_SPI1_PRIORITY,
|
||||
SPI1IrqHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the SPI peripheral.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_start(SPIDriver *spip) {
|
||||
|
||||
if (spip->state == SPI_STOP) {
|
||||
#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);
|
||||
// Setup the chip select pin
|
||||
// No bug here but control CS0 automatically anyway
|
||||
if (spip->config->ssport == AT91C_BASE_PIOA && spip->config->sspad == SPI0_CS0) {
|
||||
AT91C_BASE_PIOA->PIO_PDR = 1 << SPI0_CS0;
|
||||
AT91C_BASE_PIOA->PIO_OER = 1 << SPI0_CS0;
|
||||
AT91C_BASE_PIOA->PIO_ASR = 1 << SPI0_CS0;
|
||||
} else if (spip->config->ssport) {
|
||||
uint32_t mask;
|
||||
|
||||
mask = 1 << spip->config->sspad;
|
||||
spip->config->ssport->PIO_SODR = mask;
|
||||
spip->config->ssport->PIO_OER = mask;
|
||||
spip->config->ssport->PIO_PER = mask;
|
||||
spip->config->ssport->PIO_MDDR = mask;
|
||||
spip->config->ssport->PIO_PPUDR = mask;
|
||||
}
|
||||
}
|
||||
#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);
|
||||
// Setup the chip select pin
|
||||
// A bug in SPI1 requires that the CS be automatically controlled if it matches the CS0 pin.
|
||||
// If it is not automatically controlled SPI1 will turn off when data is written.
|
||||
// If you are not using CS0 make absolutely sure you don't use it as an output pin and
|
||||
// clear it otherwise you will get the bug in anyway.
|
||||
if (spip->config->ssport == AT91C_BASE_PIOA && spip->config->sspad == SPI1_CS0) {
|
||||
AT91C_BASE_PIOA->PIO_PDR = 1 << SPI1_CS0;
|
||||
AT91C_BASE_PIOA->PIO_OER = 1 << SPI1_CS0;
|
||||
AT91C_BASE_PIOA->PIO_BSR = 1 << SPI1_CS0;
|
||||
} else if (spip->config->ssport) {
|
||||
uint32_t mask;
|
||||
|
||||
mask = 1 << spip->config->sspad;
|
||||
spip->config->ssport->PIO_SODR = mask;
|
||||
spip->config->ssport->PIO_OER = mask;
|
||||
spip->config->ssport->PIO_PER = mask;
|
||||
spip->config->ssport->PIO_MDDR = mask;
|
||||
spip->config->ssport->PIO_PPUDR = mask;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Configuration.*/
|
||||
spip->spi->SPI_CSR[0] = spip->config->csr;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SPI peripheral.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_stop(SPIDriver *spip) {
|
||||
|
||||
if (spip->state != SPI_STOP) {
|
||||
#if AT91SAM7_SPI_USE_SPI0
|
||||
if (&SPID1 == spip) {
|
||||
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_SPI0);
|
||||
AIC_DisableIT(AT91C_ID_SPI0);
|
||||
}
|
||||
#endif
|
||||
#if AT91SAM7_SPI_USE_SPI1
|
||||
if (&SPID1 == spip) {
|
||||
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_SPI1);
|
||||
AIC_DisableIT(AT91C_ID_SPI0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Asserts the slave select signal and prepares for transfers.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_select(SPIDriver *spip) {
|
||||
|
||||
// Not needed for CS0 but it doesn't hurt either
|
||||
palClearPad(spip->config->ssport, spip->config->sspad);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deasserts the slave select signal.
|
||||
* @details The previously selected peripheral is unselected.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_unselect(SPIDriver *spip) {
|
||||
|
||||
// Not needed for CS0 but it doesn't hurt either
|
||||
palSetPad(spip->config->ssport, spip->config->sspad);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ignores data on the SPI bus.
|
||||
* @details This function transmits a series of idle words on the SPI bus and
|
||||
* ignores the received data. This function can be invoked even
|
||||
* when a slave select signal has not been yet asserted.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to be ignored
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_ignore(SPIDriver *spip, size_t n) {
|
||||
|
||||
spip->spi->SPI_TCR = n;
|
||||
spip->spi->SPI_RCR = n;
|
||||
spip->spi->SPI_TPR = (AT91_REG)idle_buf;
|
||||
spip->spi->SPI_RPR = (AT91_REG)idle_buf;
|
||||
spip->spi->SPI_IER = AT91C_SPI_ENDRX;
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
spip->spi->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges data on the SPI bus.
|
||||
* @details This function performs a simultaneous transmit/receive operation.
|
||||
* @note The buffers are organized as uint8_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to be exchanged
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
* @param[out] rxbuf the pointer to the receive buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_exchange(SPIDriver *spip, size_t n,
|
||||
const void *txbuf, void *rxbuf) {
|
||||
|
||||
spip->spi->SPI_TCR = n;
|
||||
spip->spi->SPI_RCR = n;
|
||||
spip->spi->SPI_TPR = (AT91_REG)txbuf;
|
||||
spip->spi->SPI_RPR = (AT91_REG)rxbuf;
|
||||
spip->spi->SPI_IER = AT91C_SPI_ENDRX;
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
spip->spi->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends data over the SPI bus.
|
||||
* @note The buffers are organized as uint8_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to send
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
|
||||
|
||||
spip->spi->SPI_TCR = n;
|
||||
spip->spi->SPI_RCR = n;
|
||||
spip->spi->SPI_TPR = (AT91_REG)txbuf;
|
||||
spip->spi->SPI_RPR = (AT91_REG)idle_buf;
|
||||
spip->spi->SPI_IER = AT91C_SPI_ENDRX;
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
spip->spi->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receives data from the SPI bus.
|
||||
* @note The buffers are organized as uint8_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to receive
|
||||
* @param[out] rxbuf the pointer to the receive buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
|
||||
|
||||
spip->spi->SPI_TCR = n;
|
||||
spip->spi->SPI_RCR = n;
|
||||
spip->spi->SPI_TPR = (AT91_REG)idle_buf;
|
||||
spip->spi->SPI_RPR = (AT91_REG)rxbuf;
|
||||
spip->spi->SPI_IER = AT91C_SPI_ENDRX;
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
spip->spi->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges one frame using a polled wait.
|
||||
* @details This synchronous function exchanges one frame using a polled
|
||||
* synchronization method. This function is useful when exchanging
|
||||
* small amount of data on high speed channels, usually in this
|
||||
* situation is much more efficient just wait for completion using
|
||||
* polling than suspending the thread waiting for an interrupt.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] frame the data frame to send over the SPI bus
|
||||
* @return The received data frame from the SPI bus.
|
||||
*/
|
||||
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
|
||||
|
||||
spip->spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
spip->spi->SPI_TDR = frame;
|
||||
while ((spip->spi->SPI_SR & AT91C_SPI_RDRF) == 0)
|
||||
;
|
||||
return spip->spi->SPI_RDR;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_SPI */
|
||||
|
||||
/** @} */
|
||||
234
firmware/chibios/os/hal/platforms/AT91SAM7/spi_lld.h
Executable file
234
firmware/chibios/os/hal/platforms/AT91SAM7/spi_lld.h
Executable file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AT91SAM7/spi_lld.h
|
||||
* @brief AT91SAM7 low level SPI driver header.
|
||||
*
|
||||
* @addtogroup SPI
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _SPI_LLD_H_
|
||||
#define _SPI_LLD_H_
|
||||
|
||||
#if HAL_USE_SPI || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Device compatibility.. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAM7_PLATFORM == SAM7S512 || SAM7_PLATFORM == SAM7S256 || SAM7_PLATFORM == SAM7S128 || SAM7_PLATFORM == SAM7S64
|
||||
#define SPI0_MISO AT91C_PA12_MISO
|
||||
#define SPI0_MOSI AT91C_PA13_MOSI
|
||||
#define SPI0_SCK AT91C_PA14_SPCK
|
||||
#define SPI0_CS0 11 // PA11
|
||||
#elif SAM7_PLATFORM == SAM7X512 || SAM7_PLATFORM == SAM7X256 || SAM7_PLATFORM == SAM7X128
|
||||
#define SPI0_MISO AT91C_PA16_SPI0_MISO
|
||||
#define SPI0_MOSI AT91C_PA17_SPI0_MOSI
|
||||
#define SPI0_SCK AT91C_PA18_SPI0_SPCK
|
||||
#define SPI0_CS0 12 // PA12
|
||||
#define SPI1_MISO AT91C_PA24_SPI1_MISO
|
||||
#define SPI1_MOSI AT91C_PA23_SPI1_MOSI
|
||||
#define SPI1_SCK AT91C_PA22_SPI1_SPCK
|
||||
#define SPI1_CS0 21 // PA21
|
||||
#elif SAM7_PLATFORM == SAM7A3
|
||||
#define SPI0_MISO AT91C_PA15_SPI0_MISO
|
||||
#define SPI0_MOSI AT91C_PA16_SPI0_MOSI
|
||||
#define SPI0_SCK AT91C_PA17_SPI0_SPCK
|
||||
#define SPI0_CS0 11 // PA11
|
||||
#define SPI1_MISO AT91C_PA8_SPI1_MISO
|
||||
#define SPI1_MOSI AT91C_PA9_SPI1_MOSI
|
||||
#define SPI1_SCK AT91C_PA10_SPI1_SPCK
|
||||
#define SPI1_CS0 4 // PA4
|
||||
#else
|
||||
#error "SAM7 platform not supported"
|
||||
#endif
|
||||
|
||||
#if defined (AT91C_BASE_SPI)
|
||||
#define AT91C_BASE_SPI0 AT91C_BASE_SPI
|
||||
#define AT91C_ID_SPI0 AT91C_ID_SPI
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @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(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 defined (AT91C_BASE_SPI) && AT91SAM7_SPI_USE_SPI1
|
||||
#error "SPI1 not present"
|
||||
#endif
|
||||
|
||||
#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.
|
||||
*/
|
||||
spicallback_t end_cb;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief The chip select line port.
|
||||
*/
|
||||
ioportid_t ssport;
|
||||
/**
|
||||
* @brief The chip select line pad number.
|
||||
*/
|
||||
uint16_t sspad;
|
||||
/**
|
||||
* @brief SPI Chip Select Register initialization data.
|
||||
*/
|
||||
uint32_t csr;
|
||||
} SPIConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a SPI driver.
|
||||
*/
|
||||
struct SPIDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
spistate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const SPIConfig *config;
|
||||
#if SPI_USE_WAIT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Waiting thread.
|
||||
*/
|
||||
Thread *thread;
|
||||
#endif /* SPI_USE_WAIT */
|
||||
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the bus.
|
||||
*/
|
||||
Mutex mutex;
|
||||
#elif CH_USE_SEMAPHORES
|
||||
Semaphore semaphore;
|
||||
#endif
|
||||
#endif /* SPI_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(SPI_DRIVER_EXT_FIELDS)
|
||||
SPI_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the SPIx registers block.
|
||||
*/
|
||||
AT91PS_SPI spi;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if AT91SAM7_SPI_USE_SPI0 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver SPID1;
|
||||
#endif
|
||||
|
||||
#if AT91SAM7_SPI_USE_SPI1 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver SPID2;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void spi_lld_init(void);
|
||||
void spi_lld_start(SPIDriver *spip);
|
||||
void spi_lld_stop(SPIDriver *spip);
|
||||
void spi_lld_select(SPIDriver *spip);
|
||||
void spi_lld_unselect(SPIDriver *spip);
|
||||
void spi_lld_ignore(SPIDriver *spip, size_t n);
|
||||
void spi_lld_exchange(SPIDriver *spip, size_t n,
|
||||
const void *txbuf, void *rxbuf);
|
||||
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
|
||||
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
|
||||
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_SPI */
|
||||
|
||||
#endif /* _SPI_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
Reference in New Issue
Block a user