Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,152 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup ADC ADC Driver
* @brief Generic ADC Driver.
* @details This module implements a generic ADC (Analog to Digital Converter)
* driver supporting a variety of buffer and conversion modes.
* @pre In order to use the ADC driver the @p HAL_USE_ADC option
* must be enabled in @p halconf.h.
*
* @section adc_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
rankdir="LR";
size="5, 7";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="ADC_STOP\nLow Power"];
uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"];
active [label="ADC_ACTIVE\nConverting"];
error [label="ADC_ERROR\nError"];
complete [label="ADC_COMPLETE\nComplete"];
uninit -> stop [label="\n adcInit()", constraint=false];
stop -> ready [label="\nadcStart()"];
ready -> ready [label="\nadcStart()\nadcStopConversion()"];
ready -> stop [label="\nadcStop()"];
stop -> stop [label="\nadcStop()"];
ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
active -> ready [label="\nadcStopConversion()\nsync return"];
active -> active [label="\nasync callback (half buffer, circular)\nasync callback (full buffer)\n>acg_endcb<"];
active -> complete [label="\n\nasync callback (full buffer)\n>end_cb<"];
active -> error [label="\n\nasync callback (error)\n>error_cb<"];
complete -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
complete -> ready [label="\ncallback return"];
error -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
error -> ready [label="\ncallback return"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="ADC_STOP\nLow Power"];
uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"];
active [label="ADC_ACTIVE\nConverting"];
error [label="ADC_ERROR\nError"];
complete [label="ADC_COMPLETE\nComplete"];
uninit -> stop [label="\n adcInit()", constraint=false];
stop -> ready [label="\nadcStart()"];
ready -> ready [label="\nadcStart()\nadcStopConversion()"];
ready -> stop [label="\nadcStop()"];
stop -> stop [label="\nadcStop()"];
ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
active -> ready [label="\nadcStopConversion()\nsync return"];
active -> active [label="\nasync callback (half buffer, circular)\nasync callback (full buffer)\n>acg_endcb<"];
active -> complete [label="\n\nasync callback (full buffer)\n>end_cb<"];
active -> error [label="\n\nasync callback (error)\n>error_cb<"];
complete -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
complete -> ready [label="\ncallback return"];
error -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
error -> ready [label="\ncallback return"];
}
* @enddot
* @endif
*
* @section adc_2 ADC Operations
* The ADC driver is quite complex, an explanation of the terminology and of
* the operational details follows.
*
* @subsection adc_2_1 ADC Conversion Groups
* The @p ADCConversionGroup is the objects that specifies a physical
* conversion operation. This structure contains some standard fields and
* several implementation-dependent fields.<br>
* The standard fields define the CG mode, the number of channels belonging
* to the CG and the optional callbacks.<br>
* The implementation-dependent fields specify the physical ADC operation
* mode, the analog channels belonging to the group and any other
* implementation-specific setting. Usually the extra fields just mirror
* the physical ADC registers, please refer to the vendor's MCU Reference
* Manual for details about the available settings. Details are also available
* into the documentation of the ADC low level drivers and in the various
* sample applications.
*
* @subsection adc_2_2 ADC Conversion Modes
* The driver supports several conversion modes:
* - <b>One Shot</b>, the driver performs a single group conversion then stops.
* - <b>Linear Buffer</b>, the driver performs a series of group conversions
* then stops. This mode is like a one shot conversion repeated N times,
* the buffer pointer increases after each conversion. The buffer is
* organized as an S(CG)*N samples matrix, when S(CG) is the conversion
* group size (number of channels) and N is the buffer depth (number of
* repeated conversions).
* - <b>Circular Buffer</b>, much like the linear mode but the operation does
* not stop when the buffer is filled, it is automatically restarted
* with the buffer pointer wrapping back to the buffer base.
* .
* @subsection adc_2_3 ADC Callbacks
* The driver is able to invoke callbacks during the conversion process. A
* callback is invoked when the operation has been completed or, in circular
* mode, when the buffer has been filled and the operation is restarted. In
* circular mode a callback is also invoked when the buffer is half filled.<br>
* The "half filled" and "filled" callbacks in circular mode allow to
* implement "streaming processing" of the sampled data, while the driver is
* busy filling one half of the buffer the application can process the
* other half, this allows for continuous interleaved operations.
*
* The driver is not thread safe for performance reasons, if you need to access
* the ADC bus from multiple threads then use the @p adcAcquireBus() and
* @p adcReleaseBus() APIs in order to gain exclusive access.
*
* @ingroup IO
*/

View File

@ -0,0 +1,99 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup CAN CAN Driver
* @brief Generic CAN Driver.
* @details This module implements a generic CAN (Controller Area Network)
* driver allowing the exchange of information at frame level.
* @pre In order to use the CAN driver the @p HAL_USE_CAN option
* must be enabled in @p halconf.h.
*
* @section can_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="CAN_STOP\nLow Power"];
uninit [label="CAN_UNINIT", style="bold"];
starting [label="CAN_STARTING\nInitializing"];
ready [label="CAN_READY\nClock Enabled"];
sleep [label="CAN_SLEEP\nLow Power"];
uninit -> stop [label=" canInit()", constraint=false];
stop -> stop [label="\ncanStop()"];
stop -> ready [label="\ncanStart()\n(fast implementation)"];
stop -> starting [label="\ncanStart()\n(slow implementation)"];
starting -> starting [label="\ncanStart()\n(other thread)"];
starting -> ready [label="\ninitialization complete\n(all threads)"];
ready -> stop [label="\ncanStop()"];
ready -> ready [label="\ncanStart()\ncanReceive()\ncanTransmit()"];
ready -> sleep [label="\ncanSleep()"];
sleep -> sleep [label="\ncanSleep()"];
sleep -> ready [label="\ncanWakeup()"];
sleep -> ready [label="\nhardware\nwakeup event"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="CAN_STOP\nLow Power"];
uninit [label="CAN_UNINIT", style="bold"];
starting [label="CAN_STARTING\nInitializing"];
ready [label="CAN_READY\nClock Enabled"];
sleep [label="CAN_SLEEP\nLow Power"];
uninit -> stop [label=" canInit()", constraint=false];
stop -> stop [label="\ncanStop()"];
stop -> ready [label="\ncanStart()\n(fast implementation)"];
stop -> starting [label="\ncanStart()\n(slow implementation)"];
starting -> starting [label="\ncanStart()\n(other thread)"];
starting -> ready [label="\ninitialization complete\n(all threads)"];
ready -> stop [label="\ncanStop()"];
ready -> ready [label="\ncanStart()\ncanReceive()\ncanTransmit()"];
ready -> sleep [label="\ncanSleep()"];
sleep -> sleep [label="\ncanSleep()"];
sleep -> ready [label="\ncanWakeup()"];
sleep -> ready [label="\nhardware\nwakeup event"];
}
* @enddot
* @endif
*
* @ingroup IO
*/

View File

@ -0,0 +1,91 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup EXT EXT Driver
* @brief Generic EXT Driver.
* @details This module implements a generic EXT (EXTernal) driver.
* @pre In order to use the EXT driver the @p HAL_USE_EXT option
* must be enabled in @p halconf.h.
*
* @section ext_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
uninit [label="EXT_UNINIT", style="bold"];
stop [label="EXT_STOP\nLow Power"];
active [label="EXT_ACTIVE"];
uninit -> stop [label="extInit()"];
stop -> stop [label="\nextStop()"];
stop -> active [label="\nextStart()"];
active -> stop [label="\nextStop()"];
active -> active [label="\nextStart()"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
uninit [label="EXT_UNINIT", style="bold"];
stop [label="EXT_STOP\nLow Power"];
active [label="EXT_ACTIVE"];
uninit -> stop [label="extInit()"];
stop -> stop [label="\nextStop()"];
stop -> active [label="\nextStart()"];
active -> stop [label="\nextStop()"];
active -> active [label="\nextStart()"];
}
* @enddot
* @endif
*
* @section ext_2 EXT Operations.
* This driver abstracts generic external interrupt sources, a callback
* is invoked when a programmable transition is detected on one of the
* configured channels. Several channel modes are possible.
* - <b>EXT_CH_MODE_DISABLED</b>, channel not used.
* - <b>EXT_CH_MODE_RISING_EDGE</b>, callback on a rising edge.
* - <b>EXT_CH_MODE_FALLING_EDGE</b>, callback on a falling edge.
* - <b>EXT_CH_MODE_BOTH_EDGES</b>, callback on a both edges.
* .
* @ingroup IO
*/

View File

@ -0,0 +1,85 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup GPT GPT Driver
* @brief Generic GPT Driver.
* @details This module implements a generic GPT (General Purpose Timer)
* driver. The timer can be programmed in order to trigger callbacks
* after a specified time period or continuously with a specified
* interval.
* @pre In order to use the GPT driver the @p HAL_USE_GPT option
* must be enabled in @p halconf.h.
*
* @section gpt_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="GPT_STOP\nLow Power"];
uninit [label="GPT_UNINIT", style="bold"];
ready [label="GPT_READY\nClock Enabled"];
continuous [label="GPT_CONT..S\nContinuous\nMode"];
oneshot [label="GPT_ONESHOT\nOne Shot\nMode"];
uninit -> stop [label=" gptInit()", constraint=false];
stop -> stop [label="\ngptStop()"];
stop -> ready [label="\ngptStart()"];
ready -> stop [label="\ngptStop()"];
ready -> ready [label="\ngptStart()"];
ready -> continuous [label="\ngptStartContinuous()"];
continuous -> ready [label="\ngptStopTimer()"];
continuous -> continuous [label=">callback<"];
ready -> oneshot [label="\ngptStartOneShot()\ngptPolledDelay()"];
oneshot -> ready [label="\n>callback<\nor\nDelay Over"];
}
* @enddot
*
* @section gpt_2 GPT Operations.
* This driver abstracts a generic timer composed of:
* - A clock prescaler.
* - A main up counter.
* - A comparator register that resets the main counter to zero when the limit
* is reached. A callback is invoked when this happens.
* .
* The timer can operate in three different modes:
* - <b>Continuous Mode</b>, a periodic callback is invoked until the driver
* is explicitly stopped.
* - <b>One Shot Mode</b>, a callback is invoked after the programmed period
* and then the timer automatically stops.
* - <b>Delay Mode</b>, the timer is used for inserting a brief delay into
* the execution flow, no callback is invoked in this mode.
* .
* @ingroup IO
*/

View File

@ -0,0 +1,43 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup HAL HAL Driver
* @brief Hardware Abstraction Layer.
* @details The HAL (Hardware Abstraction Layer) driver performs the system
* initialization and includes the platform support code shared by
* the other drivers. This driver does contain any API function
* except for a general initialization function @p halInit() that
* must be invoked before any HAL service can be used, usually the
* HAL initialization should be performed immediately before the
* kernel initialization.<br>
* Some HAL driver implementations also offer a custom early clock
* setup function that can be invoked before the C runtime
* initialization in order to accelerate the startup time.
*
* @ingroup IO
*/

View File

@ -0,0 +1,109 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup I2C I2C Driver
* @brief Generic I2C Driver.
* @details This module implements a generic I2C (Inter-Integrated Circuit)
* driver.
* @pre In order to use the I2C driver the @p HAL_USE_I2C option
* must be enabled in @p halconf.h.
*
* @section i2c_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="I2C_STOP\nLow Power"];
uninit [label="I2C_UNINIT", style="bold"];
ready [label="I2C_READY\nClock Enabled"];
active_tx [label="I2C_ACTIVE_TX\nBus TX Active"];
active_rx [label="I2C_ACTIVE_RX\nBus RX Active"];
locked [label="I2C_LOCKED\nBus Locked"];
uninit -> stop [label="i2cInit()", constraint=false];
stop -> stop [label="i2cStop()"];
stop -> ready [label="i2cStart()"];
ready -> ready [label="i2cStart()"];
ready -> stop [label="i2cStop()"];
ready -> active_tx [label="i2cMasterTransmit()"];
ready -> active_rx [label="i2cMasterReceive()"];
active_tx -> ready [label="completed"];
active_rx -> ready [label="completed"];
active_tx -> locked [label="RDY_TIMEOUT"];
active_rx -> locked [label="RDY_TIMEOUT"];
locked -> stop [label="i2cStop()"];
locked -> ready [label="i2cStart()"];
}
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="I2C_STOP\nLow Power"];
uninit [label="I2C_UNINIT", style="bold"];
ready [label="I2C_READY\nClock Enabled"];
active_tx [label="I2C_ACTIVE_TX\nBus TX Active"];
active_rx [label="I2C_ACTIVE_RX\nBus RX Active"];
locked [label="I2C_LOCKED\nBus Locked"];
uninit -> stop [label="i2cInit()", constraint=false];
stop -> stop [label="i2cStop()"];
stop -> ready [label="i2cStart()"];
ready -> ready [label="i2cStart()"];
ready -> stop [label="i2cStop()"];
ready -> active_tx [label="i2cMasterTransmit()"];
ready -> active_rx [label="i2cMasterReceive()"];
active_tx -> ready [label="completed"];
active_rx -> ready [label="completed"];
active_tx -> locked [label="RDY_TIMEOUT"];
active_rx -> locked [label="RDY_TIMEOUT"];
locked -> stop [label="i2cStop()"];
locked -> ready [label="i2cStart()"];
}
* @enddot
* @endif
* The driver is not thread safe for performance reasons, if you need to access
* the I2C bus from multiple threads then use the @p i2cAcquireBus() and
* @p i2cReleaseBus() APIs in order to gain exclusive access.
*
* @ingroup IO
*/

View File

@ -0,0 +1,38 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup I2S I2S Driver
* @brief Generic I2S Driver.
* @details This module implements a generic I2S driver.
* @pre In order to use the I2S driver the @p HAL_USE_I2S option
* must be enabled in @p halconf.h.
*
* @section i2s_1 Driver State Machine
*
* @ingroup IO
*/

View File

@ -0,0 +1,117 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @defgroup ICU ICU Driver
* @brief Generic ICU Driver.
* @details This module implements a generic ICU (Input Capture Unit) driver.
* @pre In order to use the ICU driver the @p HAL_USE_ICU option
* must be enabled in @p halconf.h.
*
* @section icu_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
stop [label="ICU_STOP\nLow Power"];
uninit [label="ICU_UNINIT", style="bold"];
ready [label="ICU_READY\nClock Enabled"];
waiting [label="ICU_WAITING"];
active [label="ICU_ACTIVE"];
idle [label="ICU_IDLE"];
uninit -> stop [label=" icuInit()", constraint=false];
stop -> stop [label="\nicuStop()"];
stop -> ready [label="\nicuStart()"];
ready -> stop [label="\nicuStop()"];
ready -> ready [label="\nicuStart()\nicuDisable()"];
ready -> waiting [label="\nicuEnable()"];
waiting -> active [label="\nStart Front"];
waiting -> ready [label="\nicuDisable()"];
waiting -> waiting [label="\nStop Front"];
active -> idle [label="\nStop Front\n>width_cb<"];
active -> ready [label="\nicuDisable()\nicuDisableI()"];
idle -> active [label="\nStart Front\n>period_cb<"];
idle -> ready [label="\nicuDisable()\nicuDisableI()"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
stop [label="ICU_STOP\nLow Power"];
uninit [label="ICU_UNINIT", style="bold"];
ready [label="ICU_READY\nClock Enabled"];
waiting [label="ICU_WAITING"];
active [label="ICU_ACTIVE"];
idle [label="ICU_IDLE"];
uninit -> stop [label=" icuInit()", constraint=false];
stop -> stop [label="\nicuStop()"];
stop -> ready [label="\nicuStart()"];
ready -> stop [label="\nicuStop()"];
ready -> ready [label="\nicuStart()\nicuDisable()"];
ready -> waiting [label="\nicuEnable()"];
waiting -> active [label="\nStart Front"];
waiting -> ready [label="\nicuDisable()"];
waiting -> waiting [label="\nStop Front"];
active -> idle [label="\nStop Front\n>width_cb<"];
active -> ready [label="\nicuDisable()\nicuDisableI()"];
idle -> active [label="\nStart Front\n>period_cb<"];
idle -> ready [label="\nicuDisable()\nicuDisableI()"];
}
* @enddot
* @endif
*
* @section icu_2 ICU Operations.
* This driver abstracts a generic Input Capture Unit composed of:
* - A clock prescaler.
* - A main up counter.
* - Two capture registers triggered by the rising and falling edges on
* the sampled input.
* .
* The ICU unit can be programmed to synchronize on the rising or falling
* edge of the sample input:
* - <b>ICU_INPUT_ACTIVE_HIGH</b>, a rising edge is the start signal.
* - <b>ICU_INPUT_ACTIVE_LOW</b>, a falling edge is the start signal.
* .
* After the activation the ICU unit can be in one of the following
* states at any time:
* - <b>ICU_WAITING</b>, waiting the first start signal.
* - <b>ICU_ACTIVE</b>, after a start signal.
* - <b>ICU_IDLE</b>, after a stop signal.
* .
* Callbacks are invoked when start or stop signals occur.
*
* @ingroup IO
*/

View File

@ -0,0 +1,111 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup IO_BLOCK Abstract I/O Block Device
* @ingroup IO
*
* @section io_block_1 Driver State Machine
* The drivers implementing this interface shall implement the following
* state machine internally. Not all the driver functionalities can be used
* in any moment, any transition not explicitly shown in the following
* diagram has to be considered an error and shall be captured by an
* assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
stop [label="BLK_STOP\nLow Power"];
uninit [label="BLK_UNINIT", style="bold"];
active [label="BLK_ACTIVE\nClock Enabled"];
connecting [label="BLK_CONN.ING\nConnecting"];
disconnecting [label="BLK_DISC.ING\nDisconnecting"];
ready [label="BLK_READY\nCard Ready"];
reading [label="BLK_READING\nReading"];
writing [label="BLK_WRITING\nWriting"];
uninit -> stop [label=" blkInit()", constraint=false];
stop -> stop [label="\nblkStop()"];
stop -> active [label="\nblkStart()"];
active -> stop [label="\nblkStop()"];
active -> active [label="\nblkStart()\nblkDisconnect()"];
active -> connecting [label="\nblkConnect()"];
connecting -> ready [label="\nconnection\nsuccessful"];
connecting -> ready [label="\nblkConnect()", dir="back"];
connecting -> active [label="\nconnection\nfailed"];
disconnecting -> ready [label="\nblkDisconnect()", dir="back"];
active -> disconnecting [label="\ndisconnection\nfinished", dir="back"];
ready -> reading [label="\nblkRead()"];
reading -> ready [label="\nread finished\nread error"];
ready -> writing [label="\nblkWrite()"];
writing -> ready [label="\nwrite finished\nwrite error"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Sans, fontsize=8];
stop [label="BLK_STOP\nLow Power"];
uninit [label="BLK_UNINIT", style="bold"];
active [label="BLK_ACTIVE\nClock Enabled"];
connecting [label="BLK_CONN.ING\nConnecting"];
disconnecting [label="BLK_DISC.ING\nDisconnecting"];
ready [label="BLK_READY\nCard Ready"];
reading [label="BLK_READING\nReading"];
writing [label="BLK_WRITING\nWriting"];
syncing [label="BLK_SYNCING\nSynchronizing"];
uninit -> stop [label=" blkInit()", constraint=false];
stop -> stop [label="\nblkStop()"];
stop -> active [label="\nblkStart()"];
active -> stop [label="\nblkStop()"];
active -> active [label="\nblkStart()\nblkDisconnect()"];
active -> connecting [label="\nblkConnect()"];
connecting -> ready [label="\nconnection\nsuccessful"];
connecting -> ready [label="\nblkConnect()", dir="back"];
connecting -> active [label="\nconnection\nfailed"];
disconnecting -> ready [label="\nblkDisconnect()", dir="back"];
active -> disconnecting [label="\ndisconnection\nfinished", dir="back"];
ready -> reading [label="\nblkRead()"];
reading -> ready [label="\nread finished\nread error"];
ready -> writing [label="\nblkWrite()"];
writing -> ready [label="\nwrite finished\nwrite error"];
ready -> syncing [label="\nblkSync()"];
syncing -> ready [label="\nsynchronization finished"];
}
* @enddot
* @endif
*/

View File

@ -0,0 +1,31 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup IO_CHANNEL Abstract I/O Channel
* @ingroup IO
*/

View File

@ -0,0 +1,37 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup MAC MAC Driver
* @brief Generic MAC driver.
* @details This module implements a generic MAC (Media Access Control)
* driver for Ethernet controllers.
* @pre In order to use the MAC driver the @p HAL_USE_MAC option
* must be enabled in @p halconf.h.
*
* @ingroup IO
*/

View File

@ -0,0 +1,46 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup MMC_SPI MMC over SPI Driver
* @brief Generic MMC driver.
* @details This module implements a portable MMC/SD driver that uses a SPI
* driver as physical layer. Hot plugging and removal are supported
* through kernel events.
* @pre In order to use the MMC_SPI driver the @p HAL_USE_MMC_SPI and
* @p HAL_USE_SPI options must be enabled in @p halconf.h.
*
* @section mmc_spi_1 Driver State Machine
* This driver implements a state machine internally, see the @ref IO_BLOCK
* module documentation for details.
*
* @section mmc_spi_2 Driver Operations
* This driver allows to read or write single or multiple 512 bytes blocks
* on a SD Card.
*
* @ingroup IO
*/

View File

@ -0,0 +1,35 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup MMCSD MMC/SD Block Device
* @details This module implements a common ancestor for all device drivers
* accessing MMC or SD cards. This interface inherits the state
* machine and the interface from the @ref IO_BLOCK module.
*
* @ingroup IO
*/

View File

@ -0,0 +1,81 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup PAL PAL Driver
* @brief I/O Ports Abstraction Layer
* @details This module defines an abstract interface for digital I/O ports.
* Note that most I/O ports functions are just macros. The macros
* have default software implementations that can be redefined in a
* PAL Low Level Driver if the target hardware supports special
* features like, for example, atomic bit set/reset/masking. Please
* refer to the ports specific documentation for details.<br>
* The @ref PAL has the advantage to make the access to the I/O
* ports platform independent and still be optimized for the specific
* architectures.<br>
* Note that the PAL Low Level Driver may also offer non standard
* macro and functions in order to support specific features but,
* of course, the use of such interfaces would not be portable.
* Such interfaces shall be marked with the architecture name inside
* the function names.
* @pre In order to use the PAL driver the @p HAL_USE_PAL option
* must be enabled in @p halconf.h.
*
* @section pal_1 Implementation Rules
* In implementing a PAL Low Level Driver there are some rules/behaviors that
* should be respected.
*
* @subsection pal_1_1 Writing on input pads
* The behavior is not specified but there are implementations better than
* others, this is the list of possible implementations, preferred options
* are on top:
* -# The written value is not actually output but latched, should the pads
* be reprogrammed as outputs the value would be in effect.
* -# The write operation is ignored.
* -# The write operation has side effects, as example disabling/enabling
* pull up/down resistors or changing the pad direction. This scenario is
* discouraged, please try to avoid this scenario.
* .
* @subsection pal_1_2 Reading from output pads
* The behavior is not specified but there are implementations better than
* others, this is the list of possible implementations, preferred options
* are on top:
* -# The actual pads states are read (not the output latch).
* -# The output latch value is read (regardless of the actual pads states).
* -# Unspecified, please try to avoid this scenario.
* .
* @subsection pal_1_3 Writing unused or unimplemented port bits
* The behavior is not specified.
*
* @subsection pal_1_4 Reading from unused or unimplemented port bits
* The behavior is not specified.
*
* @subsection pal_1_5 Reading or writing on pins associated to other functionalities
* The behavior is not specified.
*
* @ingroup IO
*/

View File

@ -0,0 +1,76 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup PWM PWM Driver
* @brief Generic PWM Driver.
* @details This module implements a generic PWM (Pulse Width Modulation)
* driver.
* @pre In order to use the PWM driver the @p HAL_USE_PWM option
* must be enabled in @p halconf.h.
*
* @section pwm_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
uninit [label="PWM_UNINIT", style="bold"];
stop [label="PWM_STOP\nLow Power"];
ready [label="PWM_READY\nClock Enabled"];
uninit -> stop [label="pwmInit()"];
stop -> stop [label="pwmStop()"];
stop -> ready [label="pwmStart()"];
ready -> stop [label="pwmStop()"];
ready -> ready [label="pwmEnableChannel()\npwmDisableChannel()"];
}
* @enddot
*
* @section pwm_2 PWM Operations.
* This driver abstracts a generic PWM timer composed of:
* - A clock prescaler.
* - A main up counter.
* - A comparator register that resets the main counter to zero when the limit
* is reached. An optional callback can be generated when this happens.
* - An array of @p PWM_CHANNELS PWM channels, each channel has an output,
* a comparator and is able to invoke an optional callback when a comparator
* match with the main counter happens.
* .
* A PWM channel output can be in two different states:
* - <b>IDLE</b>, when the channel is disabled or after a match occurred.
* - <b>ACTIVE</b>, when the channel is enabled and a match didn't occur yet
* in the current PWM cycle.
* .
* Note that the two states can be associated to both logical zero or one in
* the @p PWMChannelConfig structure.
*
* @ingroup IO
*/

View File

@ -0,0 +1,37 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup RTC RTC Driver
* @brief Real Time Clock Abstraction Layer
* @details This module defines an abstract interface for a Real Time Clock
* Peripheral.
* @pre In order to use the RTC driver the @p HAL_USE_RTC option
* must be enabled in @p halconf.h.
*
* @ingroup IO
*/

View File

@ -0,0 +1,44 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup SDC SDC Driver
* @brief Generic SD Card Driver.
* @details This module implements a generic SDC (Secure Digital Card) driver.
* @pre In order to use the SDC driver the @p HAL_USE_SDC option
* must be enabled in @p halconf.h.
*
* @section sdc_1 Driver State Machine
* This driver implements a state machine internally, see the @ref IO_BLOCK
* module documentation for details.
*
* @section sdc_2 Driver Operations
* This driver allows to read or write single or multiple 512 bytes blocks
* on a SD Card.
*
* @ingroup IO
*/

View File

@ -0,0 +1,68 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup SERIAL Serial Driver
* @brief Generic Serial Driver.
* @details This module implements a generic full duplex serial driver. The
* driver implements a @p SerialDriver interface and uses I/O Queues
* for communication between the upper and the lower driver. Event
* flags are used to notify the application about incoming data,
* outgoing data and other I/O events.<br>
* The module also contains functions that make the implementation
* of the interrupt service routines much easier.
* @pre In order to use the SERIAL driver the @p HAL_USE_SERIAL option
* must be enabled in @p halconf.h.
*
*
* @section serial_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
uninit [label="SD_UNINIT", style="bold"];
stop [label="SD_STOP\nLow Power"];
ready [label="SD_READY\nClock Enabled"];
uninit -> stop [label=" sdInit()"];
stop -> stop [label="\nsdStop()"];
stop -> ready [label="\nsdStart()"];
ready -> stop [label="\nsdStop()"];
ready -> ready [label="\nsdStart()"];
ready -> ready [label="\nAny I/O operation"];
}
* @enddot
*
* @ingroup IO
*/

View File

@ -0,0 +1,63 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup SERIAL_USB Serial over USB Driver
* @brief Serial over USB Driver.
* @details This module implements an USB Communication Device Class
* (CDC) as a normal serial communication port accessible from
* the device application.
* @pre In order to use the USB over Serial driver the
* @p HAL_USE_SERIAL_USB option must be enabled in @p halconf.h.
*
* @section usb_serial_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
uninit [label="SDU_UNINIT", style="bold"];
stop [label="SDU_STOP\nLow Power"];
ready [label="SDU_READY\nClock Enabled"];
uninit -> stop [label=" sduInit()"];
stop -> stop [label="\nsduStop()"];
stop -> ready [label="\nsduStart()"];
ready -> stop [label="\nsduStop()"];
ready -> ready [label="\nsduStart()"];
ready -> ready [label="\nAny I/O operation"];
}
* @enddot
*
* @ingroup IO
*/

View File

@ -0,0 +1,101 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup SPI SPI Driver
* @brief Generic SPI Driver.
* @details This module implements a generic SPI (Serial Peripheral Interface)
* driver allowing bidirectional and monodirectional transfers,
* complex atomic transactions are supported as well.
* @pre In order to use the SPI driver the @p HAL_USE_SPI option
* must be enabled in @p halconf.h.
*
* @section spi_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="SPI_STOP\nLow Power"];
uninit [label="SPI_UNINIT", style="bold"];
ready [label="SPI_READY\nClock Enabled"];
active [label="SPI_ACTIVE\nBus Active"];
complete [label="SPI_COMPLETE\nComplete"];
uninit -> stop [label="\n spiInit()", constraint=false];
stop -> ready [label="\nspiStart()"];
ready -> ready [label="\nspiSelect()\nspiUnselect()\nspiStart()"];
ready -> stop [label="\nspiStop()"];
stop -> stop [label="\nspiStop()"];
ready -> active [label="\nspiStartXXXI() (async)\nspiXXX() (sync)"];
active -> ready [label="\nsync return"];
active -> complete [label="\nasync callback\n>spc_endcb<"];
complete -> active [label="\nspiStartXXXI() (async)\nthen\ncallback return"];
complete -> ready [label="\ncallback return"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="SPI_STOP\nLow Power"];
uninit [label="SPI_UNINIT", style="bold"];
ready [label="SPI_READY\nClock Enabled"];
active [label="SPI_ACTIVE\nBus Active"];
complete [label="SPI_COMPLETE\nComplete"];
uninit -> stop [label="\n spiInit()", constraint=false];
stop -> ready [label="\nspiStart()"];
ready -> ready [label="\nspiSelect()\nspiUnselect()\nspiStart()"];
ready -> stop [label="\nspiStop()"];
stop -> stop [label="\nspiStop()"];
ready -> active [label="\nspiStartXXX() (async)\nspiXXX() (sync)"];
active -> ready [label="\nsync return"];
active -> complete [label="\nasync callback\n>spc_endcb<"];
complete -> active [label="\nspiStartXXXI() (async)\nthen\ncallback return"];
complete -> ready [label="\ncallback return"];
}
* @enddot
* @endif
*
* The driver is not thread safe for performance reasons, if you need to access
* the SPI bus from multiple threads then use the @p spiAcquireBus() and
* @p spiReleaseBus() APIs in order to gain exclusive access.
*
* @ingroup IO
*/

View File

@ -0,0 +1,38 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup TM Time Measurement Driver
*
* @brief Time Measurement unit.
* @details This module implements a time measurement mechanism able to
* monitor a portion of code and store the best/worst/last
* measurement. The measurement is performed using the realtime
* counter mechanism abstracted in the HAL driver.
*
* @ingroup IO
*/

View File

@ -0,0 +1,132 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup UART UART Driver
* @brief Generic UART Driver.
* @details This driver abstracts a generic UART (Universal Asynchronous
* Receiver Transmitter) peripheral, the API is designed to be:
* - Unbuffered and copy-less, transfers are always directly performed
* from/to the application-level buffers without extra copy
* operations.
* - Asynchronous, the API is always non blocking.
* - Callbacks capable, operations completion and other events are
* notified using callbacks.
* .
* Special hardware features like deep hardware buffers, DMA transfers
* are hidden to the user but fully supportable by the low level
* implementations.<br>
* This driver model is best used where communication events are
* meant to drive an higher level state machine, as example:
* - RS485 drivers.
* - Multipoint network drivers.
* - Serial protocol decoders.
* .
* If your application requires a synchronous buffered driver then
* the @ref SERIAL should be used instead.
* @pre In order to use the UART driver the @p HAL_USE_UART option
* must be enabled in @p halconf.h.
*
* @section uart_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
uninit [label="UART_UNINIT", style="bold"];
stop [label="UART_STOP\nLow Power"];
ready [label="UART_READY\nClock Enabled"];
uninit -> stop [label="\nuartInit()"];
stop -> ready [label="\nuartStart()"];
ready -> ready [label="\nuartStart()"];
ready -> stop [label="\nuartStop()"];
stop -> stop [label="\nuartStop()"];
}
* @enddot
*
* @subsection uart_1_1 Transmitter sub State Machine
* The follow diagram describes the transmitter state machine, this diagram
* is valid while the driver is in the @p UART_READY state. This state
* machine is automatically reset to the @p TX_IDLE state each time the
* driver enters the @p UART_READY state.
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
tx_idle [label="TX_IDLE", style="bold"];
tx_active [label="TX_ACTIVE"];
tx_complete [label="TX_COMPLETE"];
tx_fatal [label="Fatal Error", style="bold"];
tx_idle -> tx_active [label="\nuartStartSend()"];
tx_idle -> tx_idle [label="\nuartStopSend()\n>uc_txend2<"];
tx_active -> tx_complete [label="\nbuffer transmitted\n>uc_txend1<"];
tx_active -> tx_idle [label="\nuartStopSend()"];
tx_active -> tx_fatal [label="\nuartStartSend()"];
tx_complete -> tx_active [label="\nuartStartSendI()\nthen\ncallback return"];
tx_complete -> tx_idle [label="\ncallback return"];
}
* @enddot
*
* @subsection uart_1_2 Receiver sub State Machine
* The follow diagram describes the receiver state machine, this diagram
* is valid while the driver is in the @p UART_READY state. This state
* machine is automatically reset to the @p RX_IDLE state each time the
* driver enters the @p UART_READY state.
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
rx_idle [label="RX_IDLE", style="bold"];
rx_active [label="RX_ACTIVE"];
rx_complete [label="RX_COMPLETE"];
rx_fatal [label="Fatal Error", style="bold"];
rx_idle -> rx_idle [label="\nuartStopReceive()\n>uc_rxchar<\n>uc_rxerr<"];
rx_idle -> rx_active [label="\nuartStartReceive()"];
rx_active -> rx_complete [label="\nbuffer filled\n>uc_rxend<"];
rx_active -> rx_idle [label="\nuartStopReceive()"];
rx_active -> rx_active [label="\nreceive error\n>uc_rxerr<"];
rx_active -> rx_fatal [label="\nuartStartReceive()"];
rx_complete -> rx_active [label="\nuartStartReceiveI()\nthen\ncallback return"];
rx_complete -> rx_idle [label="\ncallback return"];
}
* @enddot
*
* @ingroup IO
*/

View File

@ -0,0 +1,191 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup USB USB Driver
* @brief Generic USB Driver.
* @details This module implements a generic USB (Universal Serial Bus) driver
* supporting device-mode operations.
* @pre In order to use the USB driver the @p HAL_USE_USB option
* must be enabled in @p halconf.h.
*
* @section usb_1 Driver State Machine
* The driver implements a state machine internally, not all the driver
* functionalities can be used in any moment, any transition not explicitly
* shown in the following diagram has to be considered an error and shall
* be captured by an assertion (if enabled).
* @if LATEX_PDF
* @dot
digraph example {
size="5, 7";
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="USB_STOP\nLow Power"];
uninit [label="USB_UNINIT", style="bold"];
ready [label="USB_READY\nClock Enabled"];
selected [label="\nUSB_SELECTED\naddress\nassigned"];
active [label="\nUSB_ACTIVE\nconfiguration\nselected"];
uninit -> stop [label=" usbInit()", constraint=false];
stop -> stop [label="\nusbStop()"];
stop -> ready [label="\nusbStart()"];
ready -> stop [label="\nusbStop()"];
ready -> ready [label="\n\nusbStart()"];
ready -> ready [label="\nSUSPEND/WAKEUP\n>event_cb<"];
ready -> selected [label="\nSET_ADDRESS\n>event_cb<"];
selected -> stop [label="\nusbStop()"];
selected -> ready [label="\nUSB RESET\n>event_cb<"];
selected -> selected [label="\nSUSPEND/WAKEUP\n>event_cb<\n\nValid EP0 Message\n>requests_hook_cb<\n\nGET DESCRIPTOR\n>get_descriptor_cb<"];
selected -> active [label="\nSET_CONF(n)\n>event_cb<"];
active -> stop [label="\nusbStop()"];
active -> selected [label="\nSET_CONF(0)\n>event_cb<"];
active -> active [label="\nSUSPEND/WAKEUP\n>event_cb<\n\nValid EP0 Message\n>requests_hook_cb<\n\nGET DESCRIPTOR\n>get_descriptor_cb<\n\nEndpoints Activity\n >in_cb< or >out_cb<"];
active -> ready [label="\nUSB RESET\n>event_cb<"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
stop [label="USB_STOP\nLow Power"];
uninit [label="USB_UNINIT", style="bold"];
ready [label="USB_READY\nClock Enabled"];
selected [label="\nUSB_SELECTED\naddress\nassigned"];
active [label="\nUSB_ACTIVE\nconfiguration\nselected"];
uninit -> stop [label=" usbInit()", constraint=false];
stop -> stop [label="\nusbStop()"];
stop -> ready [label="\nusbStart()"];
ready -> stop [label="\nusbStop()"];
ready -> ready [label="\n\nusbStart()"];
ready -> ready [label="\nSUSPEND/WAKEUP\n>event_cb<"];
ready -> selected [label="\nSET_ADDRESS\n>event_cb<"];
selected -> stop [label="\nusbStop()"];
selected -> ready [label="\nUSB RESET\n>event_cb<"];
selected -> selected [label="\nSUSPEND/WAKEUP\n>event_cb<\n\nValid EP0 Message\n>requests_hook_cb<\n\nGET DESCRIPTOR\n>get_descriptor_cb<"];
selected -> active [label="\nSET_CONF(n)\n>event_cb<"];
active -> stop [label="\nusbStop()"];
active -> selected [label="\nSET_CONF(0)\n>event_cb<"];
active -> active [label="\nSUSPEND/WAKEUP\n>event_cb<\n\nValid EP0 Message\n>requests_hook_cb<\n\nGET DESCRIPTOR\n>get_descriptor_cb<\n\nEndpoints Activity\n >in_cb< or >out_cb<"];
active -> ready [label="\nUSB RESET\n>event_cb<"];
}
* @enddot
* @endif
*
* @section usb_2 USB Operations
* The USB driver is quite complex and USB is complex in itself, it is
* recommended to study the USB specification before trying to use the
* driver.
*
* @subsection usb_2_1 USB Implementation
* The USB driver abstracts the inner details of the underlying USB hardware.
* The driver works asynchronously and communicates with the application
* using callbacks. The application is responsible of the descriptors and
* strings required by the USB device class to be implemented and of the
* handling of the specific messages sent over the endpoint zero. Standard
* messages are handled internally to the driver. The application can use
* hooks in order to handle custom messages or override the handling of the
* default handling of standard messages.
*
* @subsection usb_2_2 USB Endpoints
* USB endpoints are the objects that the application uses to exchange
* data with the host. There are two kind of endpoints:
* - <b>IN</b> endpoints are used by the application to transmit data to
* the host.<br>
* - <b>OUT</b> endpoints are used by the application to receive data from
* the host.
* .
* The driver invokes a callback after finishing an IN or OUT transaction.
* States diagram for OUT endpoints in transaction mode:
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
disabled [label="EP_DISABLED\nDisabled", style="bold"];
receiving [label="EP_BUSY\nReceiving"];
idle [label="EP_IDLE\nReady"];
disabled -> idle [label="\nusbInitEndpointI()"];
idle -> receiving [label="\nusbPrepareReceive()\nusbStartReceiveI()"];
receiving -> receiving [label="\nmore packets"];
receiving -> idle [label="\nreception end\n>out_cb<"];
receiving -> disabled [label="\nUSB RESET\nusbDisableEndpointsI()"];
idle -> disabled [label="\nUSB RESET\nusbDisableEndpointsI()"];
}
* @enddot
* <br><br>
* States diagram for IN endpoints in transaction mode:
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true",
width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
disabled [label="EP_DISABLED\nDisabled", style="bold"];
transmitting [label="EP_BUSY\nTransmitting"];
idle [label="EP_IDLE\nReady"];
disabled -> idle [label="\usbInitEndpointI()"];
idle -> transmitting [label="\nusbPrepareTransmit()\nusbStartTransmitI()"];
transmitting -> transmitting [label="\nmore packets"];
transmitting -> idle [label="\ntransmission end\n>in_cb<"];
transmitting -> disabled [label="\nUSB RESET\nusbDisableEndpointsI()"];
idle -> disabled [label="\nUSB RESET\nusbDisableEndpointsI()"];
}
* @enddot
* <br><br>
*
* @subsection usb_2_4 USB Callbacks
* The USB driver uses callbacks in order to interact with the application.
* There are several kinds of callbacks to be handled:
* - Driver events callback. As example errors, suspend event, reset event
* etc.
* - Messages Hook callback. This hook allows the application to implement
* handling of custom messages or to override the default handling of
* standard messages on endpoint zero.
* - Descriptor Requested callback. When the driver endpoint zero handler
* receives a GET DESCRIPTOR message and needs to send a descriptor to
* the host it queries the application using this callback.
* - Start of Frame callback. This callback is invoked each time a SOF
* packet is received.
* - Endpoint callbacks. Each endpoint informs the application about I/O
* conditions using those callbacks.
* .
*
* @ingroup IO
*/

View File

@ -0,0 +1,29 @@
# List of all the ChibiOS/RT HAL files, there is no need to remove the files
# from this list, you can disable parts of the HAL by editing halconf.h.
set(HALSRC
${CHIBIOS}/os/hal/src/hal.c
${CHIBIOS}/os/hal/src/adc.c
${CHIBIOS}/os/hal/src/can.c
${CHIBIOS}/os/hal/src/ext.c
${CHIBIOS}/os/hal/src/gpt.c
${CHIBIOS}/os/hal/src/i2c.c
${CHIBIOS}/os/hal/src/icu.c
${CHIBIOS}/os/hal/src/mac.c
${CHIBIOS}/os/hal/src/mmc_spi.c
${CHIBIOS}/os/hal/src/mmcsd.c
${CHIBIOS}/os/hal/src/pal.c
${CHIBIOS}/os/hal/src/pwm.c
${CHIBIOS}/os/hal/src/rtc.c
${CHIBIOS}/os/hal/src/sdc.c
${CHIBIOS}/os/hal/src/serial.c
${CHIBIOS}/os/hal/src/serial_usb.c
${CHIBIOS}/os/hal/src/spi.c
${CHIBIOS}/os/hal/src/tm.c
${CHIBIOS}/os/hal/src/uart.c
${CHIBIOS}/os/hal/src/usb.c
)
# Required include directories
set(HALINC
${CHIBIOS}/os/hal/include
)

View File

@ -0,0 +1,90 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @defgroup IO HAL
* @brief Hardware Abstraction Layer.
* @details Under ChibiOS/RT the set of the various device driver interfaces
* is called the HAL subsystem: Hardware Abstraction Layer. The HAL is the
* abstract interface between ChibiOS/RT application and hardware.
*
* @section hal_device_driver_arch HAL Device Drivers Architecture
* A device driver is usually split in two layers:
* - High Level Device Driver (<b>HLD</b>). This layer contains the definitions
* of the driver's APIs and the platform independent part of the driver.<br>
* An HLD is composed by two files:
* - @p @<driver@>.c, the HLD implementation file. This file must be
* included in the Makefile in order to use the driver.
* - @p @<driver@>.h, the HLD header file. This file is implicitly
* included by the HAL header file @p hal.h.
* .
* - Low Level Device Driver (<b>LLD</b>). This layer contains the platform
* dependent part of the driver.<br>
* A LLD is composed by two files:
* - @p @<driver@>_lld.c, the LLD implementation file. This file must be
* included in the Makefile in order to use the driver.
* - @p @<driver@>_lld.h, the LLD header file. This file is implicitly
* included by the HLD header file.
* .
* The LLD may be not present in those drivers that do not access the
* hardware directly but through other device drivers, as example the
* MMC_SPI driver uses the SPI and PAL drivers in order to implement
* its functionalities.
* .
* @subsection hal_device_driver_diagram Diagram
* @dot
digraph example {
graph [size="5, 7", pad="1.5, 0"];
node [shape=rectangle, fontname=Helvetica, fontsize=8,
fixedsize="true", width="2.0", height="0.4"];
edge [fontname=Helvetica, fontsize=8];
app [label="Application"];
hld [label="High Level Driver"];
lld [label="Low Level Driver"];
hw [label="Microcontroller Hardware"];
hal_lld [label="HAL shared low level code"];
app->hld;
hld->lld;
lld-> hw;
lld->hal_lld;
hal_lld->hw;
}
* @enddot
*/
/**
* @defgroup HAL_CONF Configuration
* @brief HAL Configuration.
* @details The file @p halconf.h contains the high level settings for all
* the drivers supported by the HAL. The low level, platform dependent,
* settings are contained in the @p mcuconf.h file instead and are describe
* in the various platforms reference manuals.
*
* @ingroup IO
*/

View File

@ -0,0 +1,25 @@
# List of all the ChibiOS/RT HAL files, there is no need to remove the files
# from this list, you can disable parts of the HAL by editing halconf.h.
HALSRC = ${CHIBIOS}/os/hal/src/hal.c \
${CHIBIOS}/os/hal/src/adc.c \
${CHIBIOS}/os/hal/src/can.c \
${CHIBIOS}/os/hal/src/ext.c \
${CHIBIOS}/os/hal/src/gpt.c \
${CHIBIOS}/os/hal/src/i2c.c \
${CHIBIOS}/os/hal/src/icu.c \
${CHIBIOS}/os/hal/src/mac.c \
${CHIBIOS}/os/hal/src/mmc_spi.c \
${CHIBIOS}/os/hal/src/mmcsd.c \
${CHIBIOS}/os/hal/src/pal.c \
${CHIBIOS}/os/hal/src/pwm.c \
${CHIBIOS}/os/hal/src/rtc.c \
${CHIBIOS}/os/hal/src/sdc.c \
${CHIBIOS}/os/hal/src/serial.c \
${CHIBIOS}/os/hal/src/serial_usb.c \
${CHIBIOS}/os/hal/src/spi.c \
${CHIBIOS}/os/hal/src/tm.c \
${CHIBIOS}/os/hal/src/uart.c \
${CHIBIOS}/os/hal/src/usb.c
# Required include directories
HALINC = ${CHIBIOS}/os/hal/include

View File

@ -0,0 +1,316 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file adc.h
* @brief ADC Driver macros and structures.
*
* @addtogroup ADC
* @{
*/
#ifndef _ADC_H_
#define _ADC_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name ADC configuration options
* @{
*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
#define ADC_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define ADC_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if ADC_USE_MUTUAL_EXCLUSION && !CH_USE_MUTEXES && !CH_USE_SEMAPHORES
#error "ADC_USE_MUTUAL_EXCLUSION requires CH_USE_MUTEXES and/or CH_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
ADC_UNINIT = 0, /**< Not initialized. */
ADC_STOP = 1, /**< Stopped. */
ADC_READY = 2, /**< Ready. */
ADC_ACTIVE = 3, /**< Converting. */
ADC_COMPLETE = 4, /**< Conversion complete. */
ADC_ERROR = 5 /**< Conversion complete. */
} adcstate_t;
#include "adc_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Low Level driver helper macros
* @{
*/
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_reset_i(adcp) { \
if ((adcp)->thread != NULL) { \
Thread *tp = (adcp)->thread; \
(adcp)->thread = NULL; \
tp->p_u.rdymsg = RDY_RESET; \
chSchReadyI(tp); \
} \
}
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_reset_s(adcp) { \
if ((adcp)->thread != NULL) { \
Thread *tp = (adcp)->thread; \
(adcp)->thread = NULL; \
chSchWakeupS(tp, RDY_RESET); \
} \
}
/**
* @brief Wakes up the waiting thread.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_wakeup_isr(adcp) { \
chSysLockFromIsr(); \
if ((adcp)->thread != NULL) { \
Thread *tp; \
tp = (adcp)->thread; \
(adcp)->thread = NULL; \
tp->p_u.rdymsg = RDY_OK; \
chSchReadyI(tp); \
} \
chSysUnlockFromIsr(); \
}
/**
* @brief Wakes up the waiting thread with a timeout message.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_timeout_isr(adcp) { \
chSysLockFromIsr(); \
if ((adcp)->thread != NULL) { \
Thread *tp; \
tp = (adcp)->thread; \
(adcp)->thread = NULL; \
tp->p_u.rdymsg = RDY_TIMEOUT; \
chSchReadyI(tp); \
} \
chSysUnlockFromIsr(); \
}
#else /* !ADC_USE_WAIT */
#define _adc_reset_i(adcp)
#define _adc_reset_s(adcp)
#define _adc_wakeup_isr(adcp)
#define _adc_timeout_isr(adcp)
#endif /* !ADC_USE_WAIT */
/**
* @brief Common ISR code, half buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_isr_half_code(adcp) { \
if ((adcp)->grpp->end_cb != NULL) { \
(adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth / 2); \
} \
}
/**
* @brief Common ISR code, full buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
#define _adc_isr_full_code(adcp) { \
if ((adcp)->grpp->circular) { \
/* Callback handling.*/ \
if ((adcp)->grpp->end_cb != NULL) { \
if ((adcp)->depth > 1) { \
/* Invokes the callback passing the 2nd half of the buffer.*/ \
size_t half = (adcp)->depth / 2; \
size_t half_index = half * (adcp)->grpp->num_channels; \
(adcp)->grpp->end_cb(adcp, (adcp)->samples + half_index, half); \
} \
else { \
/* Invokes the callback passing the whole buffer.*/ \
(adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth); \
} \
} \
} \
else { \
/* End conversion.*/ \
adc_lld_stop_conversion(adcp); \
if ((adcp)->grpp->end_cb != NULL) { \
(adcp)->state = ADC_COMPLETE; \
/* Invoke the callback passing the whole buffer.*/ \
(adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth); \
if ((adcp)->state == ADC_COMPLETE) { \
(adcp)->state = ADC_READY; \
(adcp)->grpp = NULL; \
} \
} \
else { \
(adcp)->state = ADC_READY; \
(adcp)->grpp = NULL; \
} \
_adc_wakeup_isr(adcp); \
} \
}
/**
* @brief Common ISR code, error event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread timeout signaling, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] adcp pointer to the @p ADCDriver object
* @param[in] err platform dependent error code
*
* @notapi
*/
#define _adc_isr_error_code(adcp, err) { \
adc_lld_stop_conversion(adcp); \
if ((adcp)->grpp->error_cb != NULL) { \
(adcp)->state = ADC_ERROR; \
(adcp)->grpp->error_cb(adcp, err); \
if ((adcp)->state == ADC_ERROR) \
(adcp)->state = ADC_READY; \
} \
(adcp)->grpp = NULL; \
_adc_timeout_isr(adcp); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void adcInit(void);
void adcObjectInit(ADCDriver *adcp);
void adcStart(ADCDriver *adcp, const ADCConfig *config);
void adcStop(ADCDriver *adcp);
void adcStartConversion(ADCDriver *adcp,
const ADCConversionGroup *grpp,
adcsample_t *samples,
size_t depth);
void adcStartConversionI(ADCDriver *adcp,
const ADCConversionGroup *grpp,
adcsample_t *samples,
size_t depth);
void adcStopConversion(ADCDriver *adcp);
void adcStopConversionI(ADCDriver *adcp);
#if ADC_USE_WAIT
msg_t adcConvert(ADCDriver *adcp,
const ADCConversionGroup *grpp,
adcsample_t *samples,
size_t depth);
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
void adcAcquireBus(ADCDriver *adcp);
void adcReleaseBus(ADCDriver *adcp);
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_H_ */
/** @} */

View File

@ -0,0 +1,165 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file can.h
* @brief CAN Driver macros and structures.
*
* @addtogroup CAN
* @{
*/
#ifndef _CAN_H_
#define _CAN_H_
#if HAL_USE_CAN || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name CAN status flags
* @{
*/
/**
* @brief Errors rate warning.
*/
#define CAN_LIMIT_WARNING 1
/**
* @brief Errors rate error.
*/
#define CAN_LIMIT_ERROR 2
/**
* @brief Bus off condition reached.
*/
#define CAN_BUS_OFF_ERROR 4
/**
* @brief Framing error of some kind on the CAN bus.
*/
#define CAN_FRAMING_ERROR 8
/**
* @brief Overflow in receive queue.
*/
#define CAN_OVERFLOW_ERROR 16
/** @} */
/**
* @brief Special mailbox identifier.
*/
#define CAN_ANY_MAILBOX 0
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name CAN configuration options
* @{
*/
/**
* @brief Sleep mode related APIs inclusion switch.
* @details This option can only be enabled if the CAN implementation supports
* the sleep mode, see the macro @p CAN_SUPPORTS_SLEEP exported by
* the underlying implementation.
*/
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
#define CAN_USE_SLEEP_MODE TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !CH_USE_SEMAPHORES || !CH_USE_EVENTS
#error "CAN driver requires CH_USE_SEMAPHORES and CH_USE_EVENTS"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
CAN_UNINIT = 0, /**< Not initialized. */
CAN_STOP = 1, /**< Stopped. */
CAN_STARTING = 2, /**< Starting. */
CAN_READY = 3, /**< Ready. */
CAN_SLEEP = 4 /**< Sleep state. */
} canstate_t;
#include "can_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Converts a mailbox index to a bit mask.
*/
#define CAN_MAILBOX_TO_MASK(mbx) (1 << ((mbx) - 1))
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void canInit(void);
void canObjectInit(CANDriver *canp);
void canStart(CANDriver *canp, const CANConfig *config);
void canStop(CANDriver *canp);
msg_t canTransmit(CANDriver *canp,
canmbx_t mailbox,
const CANTxFrame *ctfp,
systime_t timeout);
msg_t canReceive(CANDriver *canp,
canmbx_t mailbox,
CANRxFrame *crfp,
systime_t timeout);
#if CAN_USE_SLEEP_MODE
void canSleep(CANDriver *canp);
void canWakeup(CANDriver *canp);
#endif /* CAN_USE_SLEEP_MODE */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_CAN */
#endif /* _CAN_H_ */
/** @} */

View File

@ -0,0 +1,161 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file ext.h
* @brief EXT Driver macros and structures.
*
* @addtogroup EXT
* @{
*/
#ifndef _EXT_H_
#define _EXT_H_
#if HAL_USE_EXT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name EXT channel modes
* @{
*/
#define EXT_CH_MODE_EDGES_MASK 3 /**< @brief Mask of edges field. */
#define EXT_CH_MODE_DISABLED 0 /**< @brief Channel disabled. */
#define EXT_CH_MODE_RISING_EDGE 1 /**< @brief Rising edge callback. */
#define EXT_CH_MODE_FALLING_EDGE 2 /**< @brief Falling edge callback. */
#define EXT_CH_MODE_BOTH_EDGES 3 /**< @brief Both edges callback. */
#define EXT_CH_MODE_AUTOSTART 4 /**< @brief Channel started
automatically on driver start. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
EXT_UNINIT = 0, /**< Not initialized. */
EXT_STOP = 1, /**< Stopped. */
EXT_ACTIVE = 2, /**< Active. */
} extstate_t;
/**
* @brief Type of a structure representing a EXT driver.
*/
typedef struct EXTDriver EXTDriver;
#include "ext_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Enables an EXT channel.
*
* @param[in] extp pointer to the @p EXTDriver object
* @param[in] channel channel to be enabled
*
* @iclass
*/
#define extChannelEnableI(extp, channel) ext_lld_channel_enable(extp, channel)
/**
* @brief Disables an EXT channel.
*
* @param[in] extp pointer to the @p EXTDriver object
* @param[in] channel channel to be disabled
*
* @iclass
*/
#define extChannelDisableI(extp, channel) ext_lld_channel_disable(extp, channel)
/**
* @brief Changes the operation mode of a channel.
* @note This function attempts to write over the current configuration
* structure that must have been not declared constant. This
* violates the @p const qualifier in @p extStart() but it is
* intentional. This function cannot be used if the configuration
* structure is declared @p const.
*
* @param[in] extp pointer to the @p EXTDriver object
* @param[in] channel channel to be changed
* @param[in] extcp new configuration for the channel
*
* @api
*/
#define extSetChannelMode(extp, channel, extcp) { \
chSysLock(); \
extSetChannelModeI(extp, channel, extcp); \
chSysUnlock(); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void extInit(void);
void extObjectInit(EXTDriver *extp);
void extStart(EXTDriver *extp, const EXTConfig *config);
void extStop(EXTDriver *extp);
void extChannelEnable(EXTDriver *extp, expchannel_t channel);
void extChannelDisable(EXTDriver *extp, expchannel_t channel);
void extSetChannelModeI(EXTDriver *extp,
expchannel_t channel,
const EXTChannelConfig *extcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_EXT */
#endif /* _EXT_H_ */
/** @} */

View File

@ -0,0 +1,130 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file gpt.h
* @brief GPT Driver macros and structures.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_H_
#define _GPT_H_
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
GPT_UNINIT = 0, /**< Not initialized. */
GPT_STOP = 1, /**< Stopped. */
GPT_READY = 2, /**< Ready. */
GPT_CONTINUOUS = 3, /**< Active in continuous mode. */
GPT_ONESHOT = 4 /**< Active in one shot mode. */
} gptstate_t;
/**
* @brief Type of a structure representing a GPT driver.
*/
typedef struct GPTDriver GPTDriver;
/**
* @brief GPT notification callback type.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
typedef void (*gptcallback_t)(GPTDriver *gptp);
#include "gpt_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @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.
*
* @param[in] gptp pointer to a @p GPTDriver object
* @param[in] interval new cycle time in timer ticks
*
* @iclass
*/
#define gptChangeIntervalI(gptp, interval) { \
gpt_lld_change_interval(gptp, interval); \
}
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void gptInit(void);
void gptObjectInit(GPTDriver *gptp);
void gptStart(GPTDriver *gptp, const GPTConfig *config);
void gptStop(GPTDriver *gptp);
void gptStartContinuous(GPTDriver *gptp, gptcnt_t interval);
void gptStartContinuousI(GPTDriver *gptp, gptcnt_t interval);
void gptChangeInterval(GPTDriver *gptp, gptcnt_t interval);
void gptStartOneShot(GPTDriver *gptp, gptcnt_t interval);
void gptStartOneShotI(GPTDriver *gptp, gptcnt_t interval);
void gptStopTimer(GPTDriver *gptp);
void gptStopTimerI(GPTDriver *gptp);
void gptPolledDelay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_H_ */
/** @} */

View File

@ -0,0 +1,219 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file hal.h
* @brief HAL subsystem header.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_H_
#define _HAL_H_
#include "ch.h"
#include "board.h"
#include "halconf.h"
#include "hal_lld.h"
/* Abstract interfaces.*/
#include "io_channel.h"
#include "io_block.h"
/* Shared headers.*/
#include "mmcsd.h"
/* Layered drivers.*/
#include "tm.h"
#include "pal.h"
#include "adc.h"
#include "can.h"
#include "ext.h"
#include "gpt.h"
#include "i2c.h"
#include "icu.h"
#include "mac.h"
#include "pwm.h"
#include "rtc.h"
#include "serial.h"
#include "sdc.h"
#include "spi.h"
#include "uart.h"
#include "usb.h"
/* Complex drivers.*/
#include "mmc_spi.h"
#include "serial_usb.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
#if HAL_IMPLEMENTS_COUNTERS || defined(__DOXYGEN__)
/**
* @name Time conversion utilities for the realtime counter
* @{
*/
/**
* @brief Seconds to realtime ticks.
* @details Converts from seconds to realtime ticks number.
* @note The result is rounded upward to the next tick boundary.
*
* @param[in] sec number of seconds
* @return The number of ticks.
*
* @api
*/
#define S2RTT(sec) (halGetCounterFrequency() * (sec))
/**
* @brief Milliseconds to realtime ticks.
* @details Converts from milliseconds to realtime ticks number.
* @note The result is rounded upward to the next tick boundary.
*
* @param[in] msec number of milliseconds
* @return The number of ticks.
*
* @api
*/
#define MS2RTT(msec) (((halGetCounterFrequency() + 999UL) / 1000UL) * (msec))
/**
* @brief Microseconds to realtime ticks.
* @details Converts from microseconds to realtime ticks number.
* @note The result is rounded upward to the next tick boundary.
*
* @param[in] usec number of microseconds
* @return The number of ticks.
*
* @api
*/
#define US2RTT(usec) (((halGetCounterFrequency() + 999999UL) / 1000000UL) * \
(usec))
/**
* @brief Realtime ticks to seconds to.
* @details Converts from realtime ticks number to seconds.
*
* @param[in] ticks number of ticks
* @return The number of seconds.
*
* @api
*/
#define RTT2S(ticks) ((ticks) / halGetCounterFrequency())
/**
* @brief Realtime ticks to milliseconds.
* @details Converts from realtime ticks number to milliseconds.
*
* @param[in] ticks number of ticks
* @return The number of milliseconds.
*
* @api
*/
#define RTT2MS(ticks) ((ticks) / (halGetCounterFrequency() / 1000UL))
/**
* @brief Realtime ticks to microseconds.
* @details Converts from realtime ticks number to microseconds.
*
* @param[in] ticks number of ticks
* @return The number of microseconds.
*
* @api
*/
#define RTT2US(ticks) ((ticks) / (halGetCounterFrequency() / 1000000UL))
/** @} */
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the current value of the system free running counter.
* @note This is an optional service that could not be implemented in
* all HAL implementations.
* @note This function can be called from any context.
*
* @return The value of the system free running counter of
* type halrtcnt_t.
*
* @special
*/
#define halGetCounterValue() hal_lld_get_counter_value()
/**
* @brief Realtime counter frequency.
* @note This is an optional service that could not be implemented in
* all HAL implementations.
* @note This function can be called from any context.
*
* @return The realtime counter frequency of type halclock_t.
*
* @special
*/
#define halGetCounterFrequency() hal_lld_get_counter_frequency()
/** @} */
#endif /* HAL_IMPLEMENTS_COUNTERS */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void halInit(void);
#if HAL_IMPLEMENTS_COUNTERS
bool_t halIsCounterWithin(halrtcnt_t start, halrtcnt_t end);
void halPolledDelay(halrtcnt_t ticks);
#endif /* HAL_IMPLEMENTS_COUNTERS */
#ifdef __cplusplus
}
#endif
#endif /* _HAL_H_ */
/** @} */

View File

@ -0,0 +1,154 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file i2c.h
* @brief I2C Driver macros and structures.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_H_
#define _I2C_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name I2C bus error conditions
* @{
*/
#define I2CD_NO_ERROR 0x00 /**< @brief No error. */
#define I2CD_BUS_ERROR 0x01 /**< @brief Bus Error. */
#define I2CD_ARBITRATION_LOST 0x02 /**< @brief Arbitration Lost. */
#define I2CD_ACK_FAILURE 0x04 /**< @brief Acknowledge Failure. */
#define I2CD_OVERRUN 0x08 /**< @brief Overrun/Underrun. */
#define I2CD_PEC_ERROR 0x10 /**< @brief PEC Error in
reception. */
#define I2CD_TIMEOUT 0x20 /**< @brief Hardware timeout. */
#define I2CD_SMB_ALERT 0x40 /**< @brief SMBus Alert. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Enables the mutual exclusion APIs on the I2C bus.
*/
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define I2C_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if I2C_USE_MUTUAL_EXCLUSION && !CH_USE_MUTEXES && !CH_USE_SEMAPHORES
#error "I2C_USE_MUTUAL_EXCLUSION requires CH_USE_MUTEXES and/or CH_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
I2C_UNINIT = 0, /**< Not initialized. */
I2C_STOP = 1, /**< Stopped. */
I2C_READY = 2, /**< Ready. */
I2C_ACTIVE_TX = 3, /**< Transmitting. */
I2C_ACTIVE_RX = 4, /**< Receiving. */
I2C_LOCKED = 5 /**> Bus or driver locked. */
} i2cstate_t;
#include "i2c_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Wrap i2cMasterTransmitTimeout function with TIME_INFINITE timeout.
* @api
*/
#define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \
(i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \
TIME_INFINITE))
/**
* @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout.
* @api
*/
#define i2cMasterReceive(i2cp, addr, rxbuf, rxbytes) \
(i2cMasterReceiveTimeout(i2cp, addr, rxbuf, rxbytes, TIME_INFINITE))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void i2cInit(void);
void i2cObjectInit(I2CDriver *i2cp);
void i2cStart(I2CDriver *i2cp, const I2CConfig *config);
void i2cStop(I2CDriver *i2cp);
i2cflags_t i2cGetErrors(I2CDriver *i2cp);
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#if I2C_USE_MUTUAL_EXCLUSION
void i2cAcquireBus(I2CDriver *i2cp);
void i2cReleaseBus(I2CDriver *i2cp);
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C */
#endif /* _I2C_H_ */
/** @} */

View File

@ -0,0 +1,203 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file icu.h
* @brief ICU Driver macros and structures.
*
* @addtogroup ICU
* @{
*/
#ifndef _ICU_H_
#define _ICU_H_
#if HAL_USE_ICU || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
ICU_UNINIT = 0, /**< Not initialized. */
ICU_STOP = 1, /**< Stopped. */
ICU_READY = 2, /**< Ready. */
ICU_WAITING = 3, /**< Waiting first edge. */
ICU_ACTIVE = 4, /**< Active cycle phase. */
ICU_IDLE = 5, /**< Idle cycle phase. */
} icustate_t;
/**
* @brief Type of a structure representing an ICU driver.
*/
typedef struct ICUDriver ICUDriver;
/**
* @brief ICU notification callback type.
*
* @param[in] icup pointer to a @p ICUDriver object
*/
typedef void (*icucallback_t)(ICUDriver *icup);
#include "icu_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Enables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @iclass
*/
#define icuEnableI(icup) icu_lld_enable(icup)
/**
* @brief Disables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @iclass
*/
#define icuDisableI(icup) icu_lld_disable(icup)
/**
* @brief Returns the width of the latest pulse.
* @details The pulse width is defined as number of ticks between the start
* edge and the stop edge.
* @note This function is meant to be invoked from the width capture
* callback only.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @special
*/
#define icuGetWidth(icup) icu_lld_get_width(icup)
/**
* @brief Returns the width of the latest cycle.
* @details The cycle width is defined as number of ticks between a start
* edge and the next start edge.
* @note This function is meant to be invoked from the width capture
* callback only.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @special
*/
#define icuGetPeriod(icup) icu_lld_get_period(icup)
/** @} */
/**
* @name Low Level driver helper macros
* @{
*/
/**
* @brief Common ISR code, ICU width event.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
#define _icu_isr_invoke_width_cb(icup) { \
if ((icup)->state != ICU_WAITING) { \
(icup)->state = ICU_IDLE; \
(icup)->config->width_cb(icup); \
} \
}
/**
* @brief Common ISR code, ICU period event.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
#define _icu_isr_invoke_period_cb(icup) { \
icustate_t previous_state = (icup)->state; \
(icup)->state = ICU_ACTIVE; \
if (previous_state != ICU_WAITING) \
(icup)->config->period_cb(icup); \
}
/**
* @brief Common ISR code, ICU timer overflow event.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
#define _icu_isr_invoke_overflow_cb(icup) { \
(icup)->config->overflow_cb(icup); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void icuInit(void);
void icuObjectInit(ICUDriver *icup);
void icuStart(ICUDriver *icup, const ICUConfig *config);
void icuStop(ICUDriver *icup);
void icuEnable(ICUDriver *icup);
void icuDisable(ICUDriver *icup);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ICU */
#endif /* _ICU_H_ */
/** @} */

View File

@ -0,0 +1,276 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file io_block.h
* @brief I/O block devices access.
* @details This header defines an abstract interface useful to access generic
* I/O block devices in a standardized way.
*
* @addtogroup IO_BLOCK
* @details This module defines an abstract interface for accessing generic
* block devices.<br>
* Note that no code is present, just abstract interfaces-like
* structures, you should look at the system as to a set of
* abstract C++ classes (even if written in C). This system
* has then advantage to make the access to block devices
* independent from the implementation logic.
* @{
*/
#ifndef _IO_BLOCK_H_
#define _IO_BLOCK_H_
/**
* @brief Driver state machine possible states.
*/
typedef enum {
BLK_UNINIT = 0, /**< Not initialized. */
BLK_STOP = 1, /**< Stopped. */
BLK_ACTIVE = 2, /**< Interface active. */
BLK_CONNECTING = 3, /**< Connection in progress. */
BLK_DISCONNECTING = 4, /**< Disconnection in progress. */
BLK_READY = 5, /**< Device ready. */
BLK_READING = 6, /**< Read operation in progress. */
BLK_WRITING = 7, /**< Write operation in progress. */
BLK_SYNCING = 8 /**< Sync. operation in progress. */
} blkstate_t;
/**
* @brief Block device info.
*/
typedef struct {
uint32_t blk_size; /**< @brief Block size in bytes. */
uint32_t blk_num; /**< @brief Total number of blocks. */
} BlockDeviceInfo;
/**
* @brief @p BaseBlockDevice specific methods.
*/
#define _base_block_device_methods \
/* Removable media detection.*/ \
bool_t (*is_inserted)(void *instance); \
/* Removable write protection detection.*/ \
bool_t (*is_protected)(void *instance); \
/* Connection to the block device.*/ \
bool_t (*connect)(void *instance); \
/* Disconnection from the block device.*/ \
bool_t (*disconnect)(void *instance); \
/* Reads one or more blocks.*/ \
bool_t (*read)(void *instance, uint32_t startblk, \
uint8_t *buffer, uint32_t n); \
/* Writes one or more blocks.*/ \
bool_t (*write)(void *instance, uint32_t startblk, \
const uint8_t *buffer, uint32_t n); \
/* Write operations synchronization.*/ \
bool_t (*sync)(void *instance); \
/* Obtains info about the media.*/ \
bool_t (*get_info)(void *instance, BlockDeviceInfo *bdip);
/**
* @brief @p BaseBlockDevice specific data.
*/
#define _base_block_device_data \
/* Driver state.*/ \
blkstate_t state;
/**
* @brief @p BaseBlockDevice virtual methods table.
*/
struct BaseBlockDeviceVMT {
_base_block_device_methods
};
/**
* @brief Base block device class.
* @details This class represents a generic, block-accessible, device.
*/
typedef struct {
/** @brief Virtual Methods Table.*/
const struct BaseBlockDeviceVMT *vmt;
_base_block_device_data
} BaseBlockDevice;
/**
* @name Macro Functions (BaseBlockDevice)
* @{
*/
/**
* @brief Returns the driver state.
* @note Can be called in ISR context.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The driver state.
*
* @special
*/
#define blkGetDriverState(ip) ((ip)->state)
/**
* @brief Determines if the device is transferring data.
* @note Can be called in ISR context.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The driver state.
* @retval FALSE the device is not transferring data.
* @retval TRUE the device not transferring data.
*
* @special
*/
#define blkIsTransferring(ip) ((((ip)->state) == BLK_CONNECTING) || \
(((ip)->state) == BLK_DISCONNECTING) || \
(((ip)->state) == BLK_READING) || \
(((ip)->state) == BLK_WRITING))
/**
* @brief Returns the media insertion status.
* @note On some implementations this function can only be called if the
* device is not transferring data.
* The function @p blkIsTransferring() should be used before calling
* this function.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The media state.
* @retval FALSE media not inserted.
* @retval TRUE media inserted.
*
* @api
*/
#define blkIsInserted(ip) ((ip)->vmt->is_inserted(ip))
/**
* @brief Returns the media write protection status.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The media state.
* @retval FALSE writable media.
* @retval TRUE non writable media.
*
* @api
*/
#define blkIsWriteProtected(ip) ((ip)->vmt->is_protected(ip))
/**
* @brief Performs the initialization procedure on the block device.
* @details This function should be performed before I/O operations can be
* attempted on the block device and after insertion has been
* confirmed using @p blkIsInserted().
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkConnect(ip) ((ip)->vmt->connect(ip))
/**
* @brief Terminates operations on the block device.
* @details This operation safely terminates operations on the block device.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkDisconnect(ip) ((ip)->vmt->disconnect(ip))
/**
* @brief Reads one or more blocks.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
* @param[in] startblk first block to read
* @param[out] buf pointer to the read buffer
* @param[in] n number of blocks to read
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkRead(ip, startblk, buf, n) \
((ip)->vmt->read(ip, startblk, buf, n))
/**
* @brief Writes one or more blocks.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
* @param[in] startblk first block to write
* @param[out] buf pointer to the write buffer
* @param[in] n number of blocks to write
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkWrite(ip, startblk, buf, n) \
((ip)->vmt->write(ip, startblk, buf, n))
/**
* @brief Ensures write synchronization.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkSync(ip) ((ip)->vmt->sync(ip))
/**
* @brief Returns a media information structure.
*
* @param[in] ip pointer to a @p BaseBlockDevice or derived class
* @param[out] bdip pointer to a @p BlockDeviceInfo structure
*
* @return The operation status.
* @retval CH_SUCCESS operation succeeded.
* @retval CH_FAILED operation failed.
*
* @api
*/
#define blkGetInfo(ip, bdip) ((ip)->vmt->get_info(ip, bdip))
/** @} */
#endif /* _IO_BLOCK_H_ */
/** @} */

View File

@ -0,0 +1,301 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file io_channel.h
* @brief I/O channels access.
* @details This header defines an abstract interface useful to access generic
* I/O serial devices in a standardized way.
*
* @addtogroup IO_CHANNEL
* @details This module defines an abstract interface for I/O channels by
* extending the @p BaseSequentialStream interface.<br>
* Note that no code is present, I/O channels are just abstract
* interface like structures, you should look at the systems as
* to a set of abstract C++ classes (even if written in C).
* Specific device drivers can use/extend the interface and
* implement them.<br>
* This system has the advantage to make the access to channels
* independent from the implementation logic.
* @{
*/
#ifndef _IO_CHANNEL_H_
#define _IO_CHANNEL_H_
/**
* @brief @p BaseChannel specific methods.
*/
#define _base_channel_methods \
_base_sequential_stream_methods \
/* Channel put method with timeout specification.*/ \
msg_t (*putt)(void *instance, uint8_t b, systime_t time); \
/* Channel get method with timeout specification.*/ \
msg_t (*gett)(void *instance, systime_t time); \
/* Channel write method with timeout specification.*/ \
size_t (*writet)(void *instance, const uint8_t *bp, \
size_t n, systime_t time); \
/* Channel read method with timeout specification.*/ \
size_t (*readt)(void *instance, uint8_t *bp, size_t n, systime_t time);
/**
* @brief @p BaseChannel specific data.
* @note It is empty because @p BaseChannel is only an interface without
* implementation.
*/
#define _base_channel_data \
_base_sequential_stream_data
/**
* @extends BaseSequentialStreamVMT
*
* @brief @p BaseChannel virtual methods table.
*/
struct BaseChannelVMT {
_base_channel_methods
};
/**
* @extends BaseSequentialStream
*
* @brief Base channel class.
* @details This class represents a generic, byte-wide, I/O channel. This class
* introduces generic I/O primitives with timeout specification.
*/
typedef struct {
/** @brief Virtual Methods Table.*/
const struct BaseChannelVMT *vmt;
_base_channel_data
} BaseChannel;
/**
* @name Macro Functions (BaseChannel)
* @{
*/
/**
* @brief Channel blocking byte write with timeout.
* @details This function writes a byte value to a channel. If the channel
* is not ready to accept data then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] b the byte value to be written to the channel
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The operation status.
* @retval Q_OK if the operation succeeded.
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the channel associated queue (if any) was reset.
*
* @api
*/
#define chnPutTimeout(ip, b, time) ((ip)->vmt->putt(ip, b, time))
/**
* @brief Channel blocking byte read with timeout.
* @details This function reads a byte value from a channel. If the data
* is not available then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return A byte value from the queue.
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the channel associated queue (if any) has been
* reset.
*
* @api
*/
#define chnGetTimeout(ip, time) ((ip)->vmt->gett(ip, time))
/**
* @brief Channel blocking write.
* @details The function writes data from a buffer to a channel. If the channel
* is not ready to accept data then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
*
* @return The number of bytes transferred.
*
* @api
*/
#define chnWrite(ip, bp, n) chSequentialStreamWrite(ip, bp, n)
/**
* @brief Channel blocking write with timeout.
* @details The function writes data from a buffer to a channel. If the channel
* is not ready to accept data then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes transferred.
*
* @api
*/
#define chnWriteTimeout(ip, bp, n, time) ((ip)->vmt->writet(ip, bp, n, time))
/**
* @brief Channel blocking read.
* @details The function reads data from a channel into a buffer. If the data
* is not available then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
*
* @return The number of bytes transferred.
*
* @api
*/
#define chnRead(ip, bp, n) chSequentialStreamRead(ip, bp, n)
/**
* @brief Channel blocking read with timeout.
* @details The function reads data from a channel into a buffer. If the data
* is not available then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes transferred.
*
* @api
*/
#define chnReadTimeout(ip, bp, n, time) ((ip)->vmt->readt(ip, bp, n, time))
/** @} */
#if CH_USE_EVENTS || defined(__DOXYGEN__)
/**
* @name I/O status flags added to the event listener
* @{
*/
/** @brief No pending conditions.*/
#define CHN_NO_ERROR 0
/** @brief Connection happened.*/
#define CHN_CONNECTED 1
/** @brief Disconnection happened.*/
#define CHN_DISCONNECTED 2
/** @brief Data available in the input queue.*/
#define CHN_INPUT_AVAILABLE 4
/** @brief Output queue empty.*/
#define CHN_OUTPUT_EMPTY 8
/** @brief Transmission end.*/
#define CHN_TRANSMISSION_END 16
/** @} */
/**
* @brief @p BaseAsynchronousChannel specific methods.
*/
#define _base_asynchronous_channel_methods \
_base_channel_methods \
/**
* @brief @p BaseAsynchronousChannel specific data.
*/
#define _base_asynchronous_channel_data \
_base_channel_data \
/* I/O condition event source.*/ \
EventSource event;
/**
* @extends BaseChannelVMT
*
* @brief @p BaseAsynchronousChannel virtual methods table.
*/
struct BaseAsynchronousChannelVMT {
_base_asynchronous_channel_methods
};
/**
* @extends BaseChannel
*
* @brief Base asynchronous channel class.
* @details This class extends @p BaseChannel by adding event sources fields
* for asynchronous I/O for use in an event-driven environment.
*/
typedef struct {
/** @brief Virtual Methods Table.*/
const struct BaseAsynchronousChannelVMT *vmt;
_base_asynchronous_channel_data
} BaseAsynchronousChannel;
/**
* @name Macro Functions (BaseAsynchronousChannel)
* @{
*/
/**
* @brief Returns the I/O condition event source.
* @details The event source is broadcasted when an I/O condition happens.
*
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived
* class
* @return A pointer to an @p EventSource object.
*
* @api
*/
#define chnGetEventSource(ip) (&((ip)->event))
/**
* @brief Adds status flags to the listeners's flags mask.
* @details This function is usually called from the I/O ISRs in order to
* notify I/O conditions such as data events, errors, signal
* changes etc.
*
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived
* class
* @param[in] flags condition flags to be added to the listener flags mask
*
* @iclass
*/
#define chnAddFlagsI(ip, flags) { \
chEvtBroadcastFlagsI(&(ip)->event, flags); \
}
/** @} */
#endif /* CH_USE_EVENTS */
#endif /* _IO_CHANNEL_H_ */
/** @} */

View File

@ -0,0 +1,221 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file mac.h
* @brief MAC Driver macros and structures.
* @addtogroup MAC
* @{
*/
#ifndef _MAC_H_
#define _MAC_H_
#if HAL_USE_MAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name MAC configuration options
* @{
*/
/**
* @brief Enables an event sources for incoming packets.
*/
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
#define MAC_USE_ZERO_COPY FALSE
#endif
/**
* @brief Enables an event sources for incoming packets.
*/
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
#define MAC_USE_EVENTS TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !CH_USE_SEMAPHORES || !CH_USE_EVENTS
#error "the MAC driver requires CH_USE_SEMAPHORES"
#endif
#if MAC_USE_EVENTS && !CH_USE_EVENTS
#error "the MAC driver requires CH_USE_EVENTS"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
MAC_UNINIT = 0, /**< Not initialized. */
MAC_STOP = 1, /**< Stopped. */
MAC_ACTIVE = 2 /**< Active. */
} macstate_t;
/**
* @brief Type of a structure representing a MAC driver.
*/
typedef struct MACDriver MACDriver;
#include "mac_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the received frames event source.
*
* @param[in] macp pointer to the @p MACDriver object
* @return The pointer to the @p EventSource structure.
*
* @api
*/
#if MAC_USE_EVENTS || defined(__DOXYGEN__)
#define macGetReceiveEventSource(macp) (&(macp)->rdevent)
#endif
/**
* @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.
*
* @api
*/
#define macWriteTransmitDescriptor(tdp, buf, size) \
mac_lld_write_transmit_descriptor(tdp, buf, size)
/**
* @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.
*
* @api
*/
#define macReadReceiveDescriptor(rdp, buf, size) \
mac_lld_read_receive_descriptor(rdp, buf, size)
#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
/**
* @brief Returns a pointer to the next transmit buffer in the descriptor
* chain.
* @note The API guarantees that enough buffers can be requested to fill
* a whole frame.
*
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
* @param[in] size size of the requested buffer. Specify the frame size
* on the first call then scale the value down subtracting
* the amount of data already copied into the previous
* buffers.
* @param[out] sizep pointer to variable receiving the real buffer size.
* The returned value can be less than the amount
* requested, this means that more buffers must be
* requested in order to fill the frame data entirely.
* @return Pointer to the returned buffer.
*
* @api
*/
#define macGetNextTransmitBuffer(tdp, size, sizep) \
mac_lld_get_next_transmit_buffer(tdp, size, sizep)
/**
* @brief Returns a pointer to the next receive buffer in the descriptor
* chain.
* @note The API guarantees that the descriptor chain contains a whole
* frame.
*
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
* @param[out] sizep pointer to variable receiving the buffer size, it is
* zero when the last buffer has already been returned.
* @return Pointer to the returned buffer.
* @retval NULL if the buffer chain has been entirely scanned.
*
* @api
*/
#define macGetNextReceiveBuffer(rdp, sizep) \
mac_lld_get_next_receive_buffer(rdp, sizep)
#endif /* MAC_USE_ZERO_COPY */
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void macInit(void);
void macObjectInit(MACDriver *macp);
void macStart(MACDriver *macp, const MACConfig *config);
void macStop(MACDriver *macp);
void macSetAddress(MACDriver *macp, const uint8_t *p);
msg_t macWaitTransmitDescriptor(MACDriver *macp,
MACTransmitDescriptor *tdp,
systime_t time);
void macReleaseTransmitDescriptor(MACTransmitDescriptor *tdp);
msg_t macWaitReceiveDescriptor(MACDriver *macp,
MACReceiveDescriptor *rdp,
systime_t time);
void macReleaseReceiveDescriptor(MACReceiveDescriptor *rdp);
bool_t macPollLinkStatus(MACDriver *macp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_MAC */
#endif /* _MAC_H_ */
/** @} */

View File

@ -0,0 +1,169 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*-*
* @file mii.h
* @brief MII Driver macros and structures.
*
* @addtogroup MII
* @{
*/
#ifndef _MII_H_
#define _MII_H_
/*
* Generic MII registers. Note, not all registers are present on all PHY
* devices and some extra registers may be present.
*/
#define MII_BMCR 0x00 /**< Basic mode control register. */
#define MII_BMSR 0x01 /**< Basic mode status register. */
#define MII_PHYSID1 0x02 /**< PHYS ID 1. */
#define MII_PHYSID2 0x03 /**< PHYS ID 2. */
#define MII_ADVERTISE 0x04 /**< Advertisement control reg. */
#define MII_LPA 0x05 /**< Link partner ability reg. */
#define MII_EXPANSION 0x06 /**< Expansion register. */
#define MII_ANNPTR 0x07 /**< 1000BASE-T control. */
#define MII_CTRL1000 0x09 /**< 1000BASE-T control. */
#define MII_STAT1000 0x0a /**< 1000BASE-T status. */
#define MII_ESTATUS 0x0f /**< Extended Status. */
#define MII_PHYSTS 0x10 /**< PHY Status register. */
#define MII_MICR 0x11 /**< MII Interrupt ctrl register. */
#define MII_DCOUNTER 0x12 /**< Disconnect counter. */
#define MII_FCSCOUNTER 0x13 /**< False carrier counter. */
#define MII_NWAYTEST 0x14 /**< N-way auto-neg test reg. */
#define MII_RERRCOUNTER 0x15 /**< Receive error counter. */
#define MII_SREVISION 0x16 /**< Silicon revision. */
#define MII_RESV1 0x17 /**< Reserved. */
#define MII_LBRERROR 0x18 /**< Lpback, rx, bypass error. */
#define MII_PHYADDR 0x19 /**< PHY address. */
#define MII_RESV2 0x1a /**< Reserved. */
#define MII_TPISTATUS 0x1b /**< TPI status for 10Mbps. */
#define MII_NCONFIG 0x1c /**< Network interface config. */
/*
* Basic mode control register.
*/
#define BMCR_RESV 0x007f /**< Unused. */
#define BMCR_CTST 0x0080 /**< Collision test. */
#define BMCR_FULLDPLX 0x0100 /**< Full duplex. */
#define BMCR_ANRESTART 0x0200 /**< Auto negotiation restart. */
#define BMCR_ISOLATE 0x0400 /**< Disconnect DP83840 from MII. */
#define BMCR_PDOWN 0x0800 /**< Powerdown. */
#define BMCR_ANENABLE 0x1000 /**< Enable auto negotiation. */
#define BMCR_SPEED100 0x2000 /**< Select 100Mbps. */
#define BMCR_LOOPBACK 0x4000 /**< TXD loopback bit. */
#define BMCR_RESET 0x8000 /**< Reset. */
/*
* Basic mode status register.
*/
#define BMSR_ERCAP 0x0001 /**< Ext-reg capability. */
#define BMSR_JCD 0x0002 /**< Jabber detected. */
#define BMSR_LSTATUS 0x0004 /**< Link status. */
#define BMSR_ANEGCAPABLE 0x0008 /**< Able to do auto-negotiation. */
#define BMSR_RFAULT 0x0010 /**< Remote fault detected. */
#define BMSR_ANEGCOMPLETE 0x0020 /**< Auto-negotiation complete. */
#define BMSR_MFPRESUPPCAP 0x0040 /**< Able to suppress preamble. */
#define BMSR_RESV 0x0780 /**< Unused. */
#define BMSR_10HALF 0x0800 /**< Can do 10mbps, half-duplex. */
#define BMSR_10FULL 0x1000 /**< Can do 10mbps, full-duplex. */
#define BMSR_100HALF 0x2000 /**< Can do 100mbps, half-duplex. */
#define BMSR_100FULL 0x4000 /**< Can do 100mbps, full-duplex. */
#define BMSR_100BASE4 0x8000 /**< Can do 100mbps, 4k packets. */
/*
* Advertisement control register.
*/
#define ADVERTISE_SLCT 0x001f /**< Selector bits. */
#define ADVERTISE_CSMA 0x0001 /**< Only selector supported. */
#define ADVERTISE_10HALF 0x0020 /**< Try for 10mbps half-duplex. */
#define ADVERTISE_10FULL 0x0040 /**< Try for 10mbps full-duplex. */
#define ADVERTISE_100HALF 0x0080 /**< Try for 100mbps half-duplex. */
#define ADVERTISE_100FULL 0x0100 /**< Try for 100mbps full-duplex. */
#define ADVERTISE_100BASE4 0x0200 /**< Try for 100mbps 4k packets. */
#define ADVERTISE_PAUSE_CAP 0x0400 /**< Try for pause. */
#define ADVERTISE_PAUSE_ASYM 0x0800 /**< Try for asymetric pause. */
#define ADVERTISE_RESV 0x1000 /**< Unused. */
#define ADVERTISE_RFAULT 0x2000 /**< Say we can detect faults. */
#define ADVERTISE_LPACK 0x4000 /**< Ack link partners response. */
#define ADVERTISE_NPAGE 0x8000 /**< Next page bit. */
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
ADVERTISE_CSMA)
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL)
/*
* Link partner ability register.
*/
#define LPA_SLCT 0x001f /**< Same as advertise selector. */
#define LPA_10HALF 0x0020 /**< Can do 10mbps half-duplex. */
#define LPA_10FULL 0x0040 /**< Can do 10mbps full-duplex. */
#define LPA_100HALF 0x0080 /**< Can do 100mbps half-duplex. */
#define LPA_100FULL 0x0100 /**< Can do 100mbps full-duplex. */
#define LPA_100BASE4 0x0200 /**< Can do 100mbps 4k packets. */
#define LPA_PAUSE_CAP 0x0400 /**< Can pause. */
#define LPA_PAUSE_ASYM 0x0800 /**< Can pause asymetrically. */
#define LPA_RESV 0x1000 /**< Unused. */
#define LPA_RFAULT 0x2000 /**< Link partner faulted. */
#define LPA_LPACK 0x4000 /**< Link partner acked us. */
#define LPA_NPAGE 0x8000 /**< Next page bit. */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/*
* Expansion register for auto-negotiation.
*/
#define EXPANSION_NWAY 0x0001 /**< Can do N-way auto-nego. */
#define EXPANSION_LCWP 0x0002 /**< Got new RX page code word. */
#define EXPANSION_ENABLENPAGE 0x0004 /**< This enables npage words. */
#define EXPANSION_NPCAPABLE 0x0008 /**< Link partner supports npage. */
#define EXPANSION_MFAULTS 0x0010 /**< Multiple faults detected. */
#define EXPANSION_RESV 0xffe0 /**< Unused. */
/*
* N-way test register.
*/
#define NWAYTEST_RESV1 0x00ff /**< Unused. */
#define NWAYTEST_LOOPBACK 0x0100 /**< Enable loopback for N-way. */
#define NWAYTEST_RESV2 0xfe00 /**< Unused. */
/*
* PHY identifiers.
*/
#define MII_DM9161_ID 0x0181b8a0
#define MII_AM79C875_ID 0x00225540
#define MII_KS8721_ID 0x00221610
#define MII_STE101P_ID 0x00061C50
#define MII_DP83848I_ID 0x20005C90
#define MII_LAN8710A_ID 0x0007C0F1
#endif /* _MII_H_ */
/** @} */

View File

@ -0,0 +1,206 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file mmc_spi.h
* @brief MMC over SPI driver header.
*
* @addtogroup MMC_SPI
* @{
*/
#ifndef _MMC_SPI_H_
#define _MMC_SPI_H_
#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define MMC_CMD0_RETRY 10
#define MMC_CMD1_RETRY 100
#define MMC_ACMD41_RETRY 100
#define MMC_WAIT_DATA 10000
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name MMC_SPI configuration options
* @{
*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !HAL_USE_SPI || !SPI_USE_WAIT
#error "MMC_SPI driver requires HAL_USE_SPI and SPI_USE_WAIT"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief MMC/SD over SPI driver configuration structure.
*/
typedef struct {
/**
* @brief SPI driver associated to this MMC driver.
*/
SPIDriver *spip;
/**
* @brief SPI low speed configuration used during initialization.
*/
const SPIConfig *lscfg;
/**
* @brief SPI high speed configuration used during transfers.
*/
const SPIConfig *hscfg;
} MMCConfig;
/**
* @brief @p MMCDriver specific methods.
*/
#define _mmc_driver_methods \
_mmcsd_block_device_methods
/**
* @extends MMCSDBlockDeviceVMT
*
* @brief @p MMCDriver virtual methods table.
*/
struct MMCDriverVMT {
_mmc_driver_methods
};
/**
* @extends MMCSDBlockDevice
*
* @brief Structure representing a MMC/SD over SPI driver.
*/
typedef struct {
/**
* @brief Virtual Methods Table.
*/
const struct MMCDriverVMT *vmt;
_mmcsd_block_device_data
/**
* @brief Current configuration data.
*/
const MMCConfig *config;
/***
* @brief Addresses use blocks instead of bytes.
*/
bool_t block_addresses;
} MMCDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the card insertion status.
* @note This macro wraps a low level function named
* @p sdc_lld_is_card_inserted(), this function must be
* provided by the application because it is not part of the
* SDC driver.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The card state.
* @retval FALSE card not inserted.
* @retval TRUE card inserted.
*
* @api
*/
#define mmcIsCardInserted(mmcp) mmc_lld_is_card_inserted(mmcp)
/**
* @brief Returns the write protect status.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The card state.
* @retval FALSE card not inserted.
* @retval TRUE card inserted.
*
* @api
*/
#define mmcIsWriteProtected(mmcp) mmc_lld_is_write_protected(mmcp)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void mmcInit(void);
void mmcObjectInit(MMCDriver *mmcp);
void mmcStart(MMCDriver *mmcp, const MMCConfig *config);
void mmcStop(MMCDriver *mmcp);
bool_t mmcConnect(MMCDriver *mmcp);
bool_t mmcDisconnect(MMCDriver *mmcp);
bool_t mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk);
bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer);
bool_t mmcStopSequentialRead(MMCDriver *mmcp);
bool_t mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk);
bool_t mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer);
bool_t mmcStopSequentialWrite(MMCDriver *mmcp);
bool_t mmcSync(MMCDriver *mmcp);
bool_t mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip);
bool_t mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk);
bool_t mmc_lld_is_card_inserted(MMCDriver *mmcp);
bool_t mmc_lld_is_write_protected(MMCDriver *mmcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_MMC_SPI */
#endif /* _MMC_SPI_H_ */
/** @} */

View File

@ -0,0 +1,286 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file mmcsd.h
* @brief MMC/SD cards common header.
* @details This header defines an abstract interface useful to access MMC/SD
* I/O block devices in a standardized way.
*
* @addtogroup MMCSD
* @{
*/
#ifndef _MMCSD_H_
#define _MMCSD_H_
#if HAL_USE_MMC_SPI || HAL_USE_SDC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Fixed block size for MMC/SD block devices.
*/
#define MMCSD_BLOCK_SIZE 512
/**
* @brief Mask of error bits in R1 responses.
*/
#define MMCSD_R1_ERROR_MASK 0xFDFFE008
/**
* @brief Fixed pattern for CMD8.
*/
#define MMCSD_CMD8_PATTERN 0x000001AA
/**
* @name SD/MMC status conditions
* @{
*/
#define MMCSD_STS_IDLE 0
#define MMCSD_STS_READY 1
#define MMCSD_STS_IDENT 2
#define MMCSD_STS_STBY 3
#define MMCSD_STS_TRAN 4
#define MMCSD_STS_DATA 5
#define MMCSD_STS_RCV 6
#define MMCSD_STS_PRG 7
#define MMCSD_STS_DIS 8
/** @} */
/**
* @name SD/MMC commands
* @{
*/
#define MMCSD_CMD_GO_IDLE_STATE 0
#define MMCSD_CMD_INIT 1
#define MMCSD_CMD_ALL_SEND_CID 2
#define MMCSD_CMD_SEND_RELATIVE_ADDR 3
#define MMCSD_CMD_SET_BUS_WIDTH 6
#define MMCSD_CMD_SEL_DESEL_CARD 7
#define MMCSD_CMD_SEND_IF_COND 8
#define MMCSD_CMD_SEND_CSD 9
#define MMCSD_CMD_SEND_CID 10
#define MMCSD_CMD_STOP_TRANSMISSION 12
#define MMCSD_CMD_SEND_STATUS 13
#define MMCSD_CMD_SET_BLOCKLEN 16
#define MMCSD_CMD_READ_SINGLE_BLOCK 17
#define MMCSD_CMD_READ_MULTIPLE_BLOCK 18
#define MMCSD_CMD_SET_BLOCK_COUNT 23
#define MMCSD_CMD_WRITE_BLOCK 24
#define MMCSD_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMCSD_CMD_ERASE_RW_BLK_START 32
#define MMCSD_CMD_ERASE_RW_BLK_END 33
#define MMCSD_CMD_ERASE 38
#define MMCSD_CMD_APP_OP_COND 41
#define MMCSD_CMD_LOCK_UNLOCK 42
#define MMCSD_CMD_APP_CMD 55
#define MMCSD_CMD_READ_OCR 58
/** @} */
/**
* @name CSD record offsets
*/
/**
* @brief Slice position of values in CSD register.
*/
/* CSD version 2.0 */
#define MMCSD_CSD_20_CRC_SLICE 7,1
#define MMCSD_CSD_20_FILE_FORMAT_SLICE 11,10
#define MMCSD_CSD_20_TMP_WRITE_PROTECT_SLICE 12,12
#define MMCSD_CSD_20_PERM_WRITE_PROTECT_SLICE 13,13
#define MMCSD_CSD_20_COPY_SLICE 14,14
#define MMCSD_CSD_20_FILE_FORMAT_GRP_SLICE 15,15
#define MMCSD_CSD_20_WRITE_BL_PARTIAL_SLICE 21,21
#define MMCSD_CSD_20_WRITE_BL_LEN_SLICE 25,12
#define MMCSD_CSD_20_R2W_FACTOR_SLICE 28,26
#define MMCSD_CSD_20_WP_GRP_ENABLE_SLICE 31,31
#define MMCSD_CSD_20_WP_GRP_SIZE_SLICE 38,32
#define MMCSD_CSD_20_ERASE_SECTOR_SIZE_SLICE 45,39
#define MMCSD_CSD_20_ERASE_BLK_EN_SLICE 46,46
#define MMCSD_CSD_20_C_SIZE_SLICE 69,48
#define MMCSD_CSD_20_DSR_IMP_SLICE 76,76
#define MMCSD_CSD_20_READ_BLK_MISALIGN_SLICE 77,77
#define MMCSD_CSD_20_WRITE_BLK_MISALIGN_SLICE 78,78
#define MMCSD_CSD_20_READ_BL_PARTIAL_SLICE 79,79
#define MMCSD_CSD_20_READ_BL_LEN_SLICE 83,80
#define MMCSD_CSD_20_CCC_SLICE 95,84
#define MMCSD_CSD_20_TRANS_SPEED_SLICE 103,96
#define MMCSD_CSD_20_NSAC_SLICE 111,104
#define MMCSD_CSD_20_TAAC_SLICE 119,112
#define MMCSD_CSD_20_STRUCTURE_SLICE 127,126
/* CSD version 1.0 */
#define MMCSD_CSD_10_CRC_SLICE MMCSD_CSD_20_CRC_SLICE
#define MMCSD_CSD_10_FILE_FORMAT_SLICE MMCSD_CSD_20_FILE_FORMAT_SLICE
#define MMCSD_CSD_10_TMP_WRITE_PROTECT_SLICE MMCSD_CSD_20_TMP_WRITE_PROTECT_SLICE
#define MMCSD_CSD_10_PERM_WRITE_PROTECT_SLICE MMCSD_CSD_20_PERM_WRITE_PROTECT_SLICE
#define MMCSD_CSD_10_COPY_SLICE MMCSD_CSD_20_COPY_SLICE
#define MMCSD_CSD_10_FILE_FORMAT_GRP_SLICE MMCSD_CSD_20_FILE_FORMAT_GRP_SLICE
#define MMCSD_CSD_10_WRITE_BL_PARTIAL_SLICE MMCSD_CSD_20_WRITE_BL_PARTIAL_SLICE
#define MMCSD_CSD_10_WRITE_BL_LEN_SLICE MMCSD_CSD_20_WRITE_BL_LEN_SLICE
#define MMCSD_CSD_10_R2W_FACTOR_SLICE MMCSD_CSD_20_R2W_FACTOR_SLICE
#define MMCSD_CSD_10_WP_GRP_ENABLE_SLICE MMCSD_CSD_20_WP_GRP_ENABLE_SLICE
#define MMCSD_CSD_10_WP_GRP_SIZE_SLICE MMCSD_CSD_20_WP_GRP_SIZE_SLICE
#define MMCSD_CSD_10_ERASE_SECTOR_SIZE_SLICE MMCSD_CSD_20_ERASE_SECTOR_SIZE_SLICE
#define MMCSD_CSD_10_ERASE_BLK_EN_SLICE MMCSD_CSD_20_ERASE_BLK_EN_SLICE
#define MMCSD_CSD_10_C_SIZE_MULT_SLICE 49,47
#define MMCSD_CSD_10_VDD_W_CURR_MAX_SLICE 52,50
#define MMCSD_CSD_10_VDD_W_CURR_MIN_SLICE 55,53
#define MMCSD_CSD_10_VDD_R_CURR_MAX_SLICE 58,56
#define MMCSD_CSD_10_VDD_R_CURR_MIX_SLICE 61,59
#define MMCSD_CSD_10_C_SIZE_SLICE 73,62
#define MMCSD_CSD_10_DSR_IMP_SLICE MMCSD_CSD_20_DSR_IMP_SLICE
#define MMCSD_CSD_10_READ_BLK_MISALIGN_SLICE MMCSD_CSD_20_READ_BLK_MISALIGN_SLICE
#define MMCSD_CSD_10_WRITE_BLK_MISALIGN_SLICE MMCSD_CSD_20_WRITE_BLK_MISALIGN_SLICE
#define MMCSD_CSD_10_READ_BL_PARTIAL_SLICE MMCSD_CSD_20_READ_BL_PARTIAL_SLICE
#define MMCSD_CSD_10_READ_BL_LEN_SLICE 83, 80
#define MMCSD_CSD_10_CCC_SLICE MMCSD_CSD_20_CCC_SLICE
#define MMCSD_CSD_10_TRANS_SPEED_SLICE MMCSD_CSD_20_TRANS_SPEED_SLICE
#define MMCSD_CSD_10_NSAC_SLICE MMCSD_CSD_20_NSAC_SLICE
#define MMCSD_CSD_10_TAAC_SLICE MMCSD_CSD_20_TAAC_SLICE
#define MMCSD_CSD_10_STRUCTURE_SLICE MMCSD_CSD_20_STRUCTURE_SLICE
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief @p MMCSDBlockDevice specific methods.
*/
#define _mmcsd_block_device_methods \
_base_block_device_methods
/**
* @brief @p MMCSDBlockDevice specific data.
* @note It is empty because @p MMCSDBlockDevice is only an interface
* without implementation.
*/
#define _mmcsd_block_device_data \
_base_block_device_data \
/* Card CID.*/ \
uint32_t cid[4]; \
/* Card CSD.*/ \
uint32_t csd[4]; \
/* Total number of blocks in card.*/ \
uint32_t capacity;
/**
* @extends BaseBlockDeviceVMT
*
* @brief @p MMCSDBlockDevice virtual methods table.
*/
struct MMCSDBlockDeviceVMT {
_base_block_device_methods
};
/**
* @extends BaseBlockDevice
*
* @brief MCC/SD block device class.
* @details This class represents a, block-accessible, MMC/SD device.
*/
typedef struct {
/** @brief Virtual Methods Table.*/
const struct MMCSDBlockDeviceVMT *vmt;
_mmcsd_block_device_data
} MMCSDBlockDevice;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name R1 response utilities
* @{
*/
/**
* @brief Evaluates to @p TRUE if the R1 response contains error flags.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_ERROR(r1) (((r1) & MMCSD_R1_ERROR_MASK) != 0)
/**
* @brief Returns the status field of an R1 response.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_STS(r1) (((r1) >> 9) & 15)
/**
* @brief Evaluates to @p TRUE if the R1 response indicates a locked card.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_IS_CARD_LOCKED(r1) (((r1) >> 21) & 1)
/** @} */
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the card capacity in blocks.
*
* @param[in] ip pointer to a @p MMCSDBlockDevice or derived class
*
* @return The card capacity.
*
* @api
*/
#define mmcsdGetCardCapacity(ip) ((ip)->capacity)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
uint32_t mmcsdGetCapacity(uint32_t csd[4]);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_MMC_SPI || HAL_USE_MMC_SDC*/
#endif /* _MMCSD_H_ */
/** @} */

View File

@ -0,0 +1,562 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file pal.h
* @brief I/O Ports Abstraction Layer macros, types and structures.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_H_
#define _PAL_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Pads mode constants
* @{
*/
/**
* @brief After reset state.
* @details The state itself is not specified and is architecture dependent,
* it is guaranteed to be equal to the after-reset state. It is
* usually an input state.
*/
#define PAL_MODE_RESET 0
/**
* @brief Safe state for <b>unconnected</b> pads.
* @details The state itself is not specified and is architecture dependent,
* it may be mapped on @p PAL_MODE_INPUT_PULLUP,
* @p PAL_MODE_INPUT_PULLDOWN or @p PAL_MODE_OUTPUT_PUSHPULL for
* example.
*/
#define PAL_MODE_UNCONNECTED 1
/**
* @brief Regular input high-Z pad.
*/
#define PAL_MODE_INPUT 2
/**
* @brief Input pad with weak pull up resistor.
*/
#define PAL_MODE_INPUT_PULLUP 3
/**
* @brief Input pad with weak pull down resistor.
*/
#define PAL_MODE_INPUT_PULLDOWN 4
/**
* @brief Analog input mode.
*/
#define PAL_MODE_INPUT_ANALOG 5
/**
* @brief Push-pull output pad.
*/
#define PAL_MODE_OUTPUT_PUSHPULL 6
/**
* @brief Open-drain output pad.
*/
#define PAL_MODE_OUTPUT_OPENDRAIN 7
/** @} */
/**
* @name Logic level constants
* @{
*/
/**
* @brief Logical low state.
*/
#define PAL_LOW 0
/**
* @brief Logical high state.
*/
#define PAL_HIGH 1
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
#include "pal_lld.h"
/**
* @brief I/O bus descriptor.
* @details This structure describes a group of contiguous digital I/O lines
* that have to be handled as bus.
* @note I/O operations on a bus do not affect I/O lines on the same port but
* not belonging to the bus.
*/
typedef struct {
/**
* @brief Port identifier.
*/
ioportid_t portid;
/**
* @brief Bus mask aligned to port bit 0.
* @note The bus mask implicitly define the bus width. A logical AND is
* performed on the bus data.
*/
ioportmask_t mask;
/**
* @brief Offset, within the port, of the least significant bit of the bus.
*/
uint_fast8_t offset;
} IOBus;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Port bit helper macro.
* @details This macro calculates the mask of a bit within a port.
*
* @param[in] n bit position within the port
* @return The bit mask.
*/
#if !defined(PAL_PORT_BIT) || defined(__DOXYGEN__)
#define PAL_PORT_BIT(n) ((ioportmask_t)(1 << (n)))
#endif
/**
* @brief Bits group mask helper.
* @details This macro calculates the mask of a bits group.
*
* @param[in] width group width
* @return The group mask.
*/
#if !defined(PAL_GROUP_MASK) || defined(__DOXYGEN__)
#define PAL_GROUP_MASK(width) ((ioportmask_t)(1 << (width)) - 1)
#endif
/**
* @brief Data part of a static I/O bus initializer.
* @details This macro should be used when statically initializing an I/O bus
* that is part of a bigger structure.
*
* @param[in] name name of the IOBus variable
* @param[in] port I/O port descriptor
* @param[in] width bus width in bits
* @param[in] offset bus bit offset within the port
*/
#define _IOBUS_DATA(name, port, width, offset) \
{port, PAL_GROUP_MASK(width), offset}
/**
* @brief Static I/O bus initializer.
*
* @param[in] name name of the IOBus variable
* @param[in] port I/O port descriptor
* @param[in] width bus width in bits
* @param[in] offset bus bit offset within the port
*/
#define IOBUS_DECL(name, port, width, offset) \
IOBus name = _IOBUS_DATA(name, port, width, offset)
/**
* @name Macro Functions
* @{
*/
/**
* @brief PAL subsystem initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @param[in] config pointer to an architecture specific configuration
* structure. This structure is defined in the low level driver
* header.
*
* @init
*/
#define palInit(config) pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
* @note The default implementation always return zero and computes the
* parameter eventual side effects.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @return The port logical states.
*
* @special
*/
#if !defined(pal_lld_readport) || defined(__DOXYGEN__)
#define palReadPort(port) ((void)(port), 0)
#else
#define palReadPort(port) pal_lld_readport(port)
#endif
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
* @note The default implementation always return zero and computes the
* parameter eventual side effects.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @special
*/
#if !defined(pal_lld_readlatch) || defined(__DOXYGEN__)
#define palReadLatch(port) ((void)(port), 0)
#else
#define palReadLatch(port) pal_lld_readlatch(port)
#endif
/**
* @brief Writes a bits mask on a I/O port.
* @note The default implementation does nothing except computing the
* parameters eventual side effects.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @special
*/
#if !defined(pal_lld_writeport) || defined(__DOXYGEN__)
#define palWritePort(port, bits) ((void)(port), (void)(bits))
#else
#define palWritePort(port, bits) pal_lld_writeport(port, bits)
#endif
/**
* @brief Sets a bits mask on a I/O port.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @special
*/
#if !defined(pal_lld_setport) || defined(__DOXYGEN__)
#define palSetPort(port, bits) \
palWritePort(port, palReadLatch(port) | (bits))
#else
#define palSetPort(port, bits) pal_lld_setport(port, bits)
#endif
/**
* @brief Clears a bits mask on a I/O port.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @special
*/
#if !defined(pal_lld_clearport) || defined(__DOXYGEN__)
#define palClearPort(port, bits) \
palWritePort(port, palReadLatch(port) & ~(bits))
#else
#define palClearPort(port, bits) pal_lld_clearport(port, bits)
#endif
/**
* @brief Toggles a bits mask on a I/O port.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] bits bits to be XORed on the specified port
*
* @special
*/
#if !defined(pal_lld_toggleport) || defined(__DOXYGEN__)
#define palTogglePort(port, bits) \
palWritePort(port, palReadLatch(port) ^ (bits))
#else
#define palTogglePort(port, bits) pal_lld_toggleport(port, bits)
#endif
/**
* @brief Reads a group of bits.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] mask group mask, a logical AND is performed on the input
* data
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @special
*/
#if !defined(pal_lld_readgroup) || defined(__DOXYGEN__)
#define palReadGroup(port, mask, offset) \
((palReadPort(port) >> (offset)) & (mask))
#else
#define palReadGroup(port, mask, offset) pal_lld_readgroup(port, mask, offset)
#endif
/**
* @brief Writes a group of bits.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] mask group mask, a logical AND is performed on the
* output data
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group
* width are masked.
*
* @special
*/
#if !defined(pal_lld_writegroup) || defined(__DOXYGEN__)
#define palWriteGroup(port, mask, offset, bits) \
palWritePort(port, (palReadLatch(port) & ~((mask) << (offset))) | \
(((bits) & (mask)) << (offset)))
#else
#define palWriteGroup(port, mask, offset, bits) \
pal_lld_writegroup(port, mask, offset, bits)
#endif
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @special
*/
#if !defined(pal_lld_setgroupmode) || defined(__DOXYGEN__)
#define palSetGroupMode(port, mask, offset, mode)
#else
#define palSetGroupMode(port, mask, offset, mode) \
pal_lld_setgroupmode(port, mask, offset, mode)
#endif
/**
* @brief Reads an input pad logical state.
* @note The default implementation not necessarily optimal. Low level
* drivers may optimize the function by using specific hardware
* or coding.
* @note The default implementation internally uses the @p palReadPort().
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @return The logical state.
* @retval PAL_LOW low logical state.
* @retval PAL_HIGH high logical state.
*
* @special
*/
#if !defined(pal_lld_readpad) || defined(__DOXYGEN__)
#define palReadPad(port, pad) ((palReadPort(port) >> (pad)) & 1)
#else
#define palReadPad(port, pad) pal_lld_readpad(port, pad)
#endif
/**
* @brief Writes a logical state on an output pad.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The default implementation internally uses the @p palReadLatch()
* and @p palWritePort().
* @note The function can be called from any context.
*
* @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
*
* @special
*/
#if !defined(pal_lld_writepad) || defined(__DOXYGEN__)
#define palWritePad(port, pad, bit) \
palWritePort(port, (palReadLatch(port) & ~PAL_PORT_BIT(pad)) | \
(((bit) & 1) << pad))
#else
#define palWritePad(port, pad, bit) pal_lld_writepad(port, pad, bit)
#endif
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The default implementation internally uses the @p palSetPort().
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @special
*/
#if !defined(pal_lld_setpad) || defined(__DOXYGEN__)
#define palSetPad(port, pad) palSetPort(port, PAL_PORT_BIT(pad))
#else
#define palSetPad(port, pad) pal_lld_setpad(port, pad)
#endif
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The default implementation internally uses the @p palClearPort().
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @special
*/
#if !defined(pal_lld_clearpad) || defined(__DOXYGEN__)
#define palClearPad(port, pad) palClearPort(port, PAL_PORT_BIT(pad))
#else
#define palClearPad(port, pad) pal_lld_clearpad(port, pad)
#endif
/**
* @brief Toggles a pad logical state.
* @note The operation is not guaranteed to be atomic on all the
* architectures, for atomicity and/or portability reasons you may
* need to enclose port I/O operations between @p chSysLock() and
* @p chSysUnlock().
* @note The default implementation is non atomic and not necessarily
* optimal. Low level drivers may optimize the function by using
* specific hardware or coding.
* @note The default implementation internally uses the @p palTogglePort().
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @special
*/
#if !defined(pal_lld_togglepad) || defined(__DOXYGEN__)
#define palTogglePad(port, pad) palTogglePort(port, PAL_PORT_BIT(pad))
#else
#define palTogglePad(port, pad) pal_lld_togglepad(port, pad)
#endif
/**
* @brief Pad mode setup.
* @details This function programs a pad with the specified mode.
* @note The default implementation not necessarily optimal. Low level
* drivers may optimize the function by using specific hardware
* or coding.
* @note Programming an unknown or unsupported mode is silently ignored.
* @note The function can be called from any context.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] mode pad mode
*
* @special
*/
#if !defined(pal_lld_setpadmode) || defined(__DOXYGEN__)
#define palSetPadMode(port, pad, mode) \
palSetGroupMode(port, PAL_PORT_BIT(pad), 0, mode)
#else
#define palSetPadMode(port, pad, mode) pal_lld_setpadmode(port, pad, mode)
#endif
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
ioportmask_t palReadBus(IOBus *bus);
void palWriteBus(IOBus *bus, ioportmask_t bits);
void palSetBusMode(IOBus *bus, iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* _PAL_H_ */
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -0,0 +1,259 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file pwm.h
* @brief PWM Driver macros and structures.
*
* @addtogroup PWM
* @{
*/
#ifndef _PWM_H_
#define _PWM_H_
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name PWM output mode macros
* @{
*/
/**
* @brief Standard output modes mask.
*/
#define PWM_OUTPUT_MASK 0x0F
/**
* @brief Output not driven, callback only.
*/
#define PWM_OUTPUT_DISABLED 0x00
/**
* @brief Positive PWM logic, active is logic level one.
*/
#define PWM_OUTPUT_ACTIVE_HIGH 0x01
/**
* @brief Inverse PWM logic, active is logic level zero.
*/
#define PWM_OUTPUT_ACTIVE_LOW 0x02
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
PWM_UNINIT = 0, /**< Not initialized. */
PWM_STOP = 1, /**< Stopped. */
PWM_READY = 2, /**< Ready. */
} pwmstate_t;
/**
* @brief Type of a structure representing a PWM driver.
*/
typedef struct PWMDriver PWMDriver;
/**
* @brief PWM notification callback type.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*/
typedef void (*pwmcallback_t)(PWMDriver *pwmp);
#include "pwm_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name PWM duty cycle conversion
* @{
*/
/**
* @brief Converts from fraction to pulse width.
* @note Be careful with rounding errors, this is integer math not magic.
* You can specify tenths of thousandth but make sure you have the
* proper hardware resolution by carefully choosing the clock source
* and prescaler settings, see @p PWM_COMPUTE_PSC.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] denominator denominator of the fraction
* @param[in] numerator numerator of the fraction
* @return The pulse width to be passed to @p pwmEnableChannel().
*
* @api
*/
#define PWM_FRACTION_TO_WIDTH(pwmp, denominator, numerator) \
((pwmcnt_t)((((pwmcnt_t)(pwmp)->period) * \
(pwmcnt_t)(numerator)) / (pwmcnt_t)(denominator)))
/**
* @brief Converts from degrees to pulse width.
* @note Be careful with rounding errors, this is integer math not magic.
* You can specify hundredths of degrees but make sure you have the
* proper hardware resolution by carefully choosing the clock source
* and prescaler settings, see @p PWM_COMPUTE_PSC.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] degrees degrees as an integer between 0 and 36000
* @return The pulse width to be passed to @p pwmEnableChannel().
*
* @api
*/
#define PWM_DEGREES_TO_WIDTH(pwmp, degrees) \
PWM_FRACTION_TO_WIDTH(pwmp, 36000, degrees)
/**
* @brief Converts from percentage to pulse width.
* @note Be careful with rounding errors, this is integer math not magic.
* You can specify tenths of thousandth but make sure you have the
* proper hardware resolution by carefully choosing the clock source
* and prescaler settings, see @p PWM_COMPUTE_PSC.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] percentage percentage as an integer between 0 and 10000
* @return The pulse width to be passed to @p pwmEnableChannel().
*
* @api
*/
#define PWM_PERCENTAGE_TO_WIDTH(pwmp, percentage) \
PWM_FRACTION_TO_WIDTH(pwmp, 10000, percentage)
/** @} */
/**
* @name Macro Functions
* @{
*/
/**
* @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 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] value new cycle time in ticks
*
* @iclass
*/
#define pwmChangePeriodI(pwmp, value) { \
(pwmp)->period = (value); \
pwm_lld_change_period(pwmp, value); \
}
/**
* @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
*
* @iclass
*/
#define pwmEnableChannelI(pwmp, channel, width) \
pwm_lld_enable_channel(pwmp, channel, width)
/**
* @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)
*
* @iclass
*/
#define pwmDisableChannelI(pwmp, channel) \
pwm_lld_disable_channel(pwmp, channel)
/**
* @brief Returns a PWM channel status.
* @pre The PWM unit must have been activated using @p pwmStart().
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
*
* @iclass
*/
#define pwmIsChannelEnabledI(pwmp, channel) \
pwm_lld_is_channel_enabled(pwmp, channel)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void pwmInit(void);
void pwmObjectInit(PWMDriver *pwmp);
void pwmStart(PWMDriver *pwmp, const PWMConfig *config);
void pwmStop(PWMDriver *pwmp);
void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period);
void pwmEnableChannel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PWM */
#endif /* _PWM_H_ */
/** @} */

View File

@ -0,0 +1,178 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file rtc.h
* @brief RTC Driver macros and structures.
*
* @addtogroup RTC
* @{
*/
#ifndef _RTC_H_
#define _RTC_H_
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Date/Time bit masks
* @{
*/
#define RTC_TIME_SECONDS_MASK 0x0000001F /* @brief Seconds mask. */
#define RTC_TIME_MINUTES_MASK 0x000007E0 /* @brief Minutes mask. */
#define RTC_TIME_HOURS_MASK 0x0000F800 /* @brief Hours mask. */
#define RTC_DATE_DAYS_MASK 0x001F0000 /* @brief Days mask. */
#define RTC_DATE_MONTHS_MASK 0x01E00000 /* @brief Months mask. */
#define RTC_DATE_YEARS_MASK 0xFE000000 /* @brief Years mask. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an RTC driver.
*/
typedef struct RTCDriver RTCDriver;
/**
* @brief Type of a structure representing an RTC time stamp.
*/
typedef struct RTCTime RTCTime;
#include "rtc_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Set current time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] timespec pointer to a @p RTCTime structure
*
* @iclass
*/
#define rtcSetTimeI(rtcp, timespec) rtc_lld_set_time(rtcp, timespec)
/**
* @brief Get current time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[out] timespec pointer to a @p RTCTime structure
*
* @iclass
*/
#define rtcGetTimeI(rtcp, timespec) rtc_lld_get_time(rtcp, timespec)
#if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
/**
* @brief Set alarm time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] alarm alarm identifier
* @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL
*
* @iclass
*/
#define rtcSetAlarmI(rtcp, alarm, alarmspec) \
rtc_lld_set_alarm(rtcp, alarm, alarmspec)
/**
* @brief Get current alarm.
* @note If an alarm has not been set then the returned alarm specification
* is not meaningful.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] alarm alarm identifier
* @param[out] alarmspec pointer to a @p RTCAlarm structure
*
* @iclass
*/
#define rtcGetAlarmI(rtcp, alarm, alarmspec) \
rtc_lld_get_alarm(rtcp, alarm, alarmspec)
#endif /* RTC_ALARMS > 0 */
#if RTC_SUPPORTS_CALLBACKS || defined(__DOXYGEN__)
/**
* @brief Enables or disables RTC callbacks.
* @details This function enables or disables the callback, use a @p NULL
* pointer in order to disable it.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] callback callback function pointer or @p NULL
*
* @iclass
*/
#define rtcSetCallbackI(rtcp, callback) rtc_lld_set_callback(rtcp, callback)
#endif /* RTC_SUPPORTS_CALLBACKS */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void rtcInit(void);
void rtcSetTime(RTCDriver *rtcp, const RTCTime *timespec);
void rtcGetTime(RTCDriver *rtcp, RTCTime *timespec);
#if RTC_ALARMS > 0
void rtcSetAlarm(RTCDriver *rtcp,
rtcalarm_t alarm,
const RTCAlarm *alarmspec);
void rtcGetAlarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec);
#endif
uint32_t rtcGetTimeFat(RTCDriver *rtcp);
#if RTC_SUPPORTS_CALLBACKS
void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_RTC */
#endif /* _RTC_H_ */
/** @} */

View File

@ -0,0 +1,189 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file sdc.h
* @brief SDC Driver macros and structures.
*
* @addtogroup SDC
* @{
*/
#ifndef _SDC_H_
#define _SDC_H_
#if HAL_USE_SDC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name SD cart types
* @{
*/
#define SDC_MODE_CARDTYPE_MASK 0xF /**< @brief Card type mask. */
#define SDC_MODE_CARDTYPE_SDV11 0 /**< @brief Card is SD V1.1.*/
#define SDC_MODE_CARDTYPE_SDV20 1 /**< @brief Card is SD V2.0.*/
#define SDC_MODE_CARDTYPE_MMC 2 /**< @brief Card is MMC. */
#define SDC_MODE_HIGH_CAPACITY 0x10 /**< @brief High cap.card. */
/** @} */
/**
* @name SDC bus error conditions
* @{
*/
#define SDC_NO_ERROR 0 /**< @brief No error. */
#define SDC_CMD_CRC_ERROR 1 /**< @brief Command CRC error. */
#define SDC_DATA_CRC_ERROR 2 /**< @brief Data CRC error. */
#define SDC_DATA_TIMEOUT 4 /**< @brief HW write timeout. */
#define SDC_COMMAND_TIMEOUT 8 /**< @brief HW read timeout. */
#define SDC_TX_UNDERRUN 16 /**< @brief TX buffer underrun. */
#define SDC_RX_OVERRUN 32 /**< @brief RX buffer overrun. */
#define SDC_STARTBIT_ERROR 64 /**< @brief Start bit missing. */
#define SDC_OVERFLOW_ERROR 128 /**< @brief Card overflow error. */
#define SDC_UNHANDLED_ERROR 0xFFFFFFFF
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SDC configuration options
* @{
*/
/**
* @brief Number of initialization attempts before rejecting the card.
* @note Attempts are performed at 10mS intervals.
*/
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
#define SDC_INIT_RETRY 100
#endif
/**
* @brief Include support for MMC cards.
* @note MMC support is not yet implemented so this option must be kept
* at @p FALSE.
*/
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
#define SDC_MMC_SUPPORT FALSE
#endif
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
*/
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
#define SDC_NICE_WAITING TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
#include "sdc_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the card insertion status.
* @note This macro wraps a low level function named
* @p sdc_lld_is_card_inserted(), this function must be
* provided by the application because it is not part of the
* SDC driver.
*
* @param[in] sdcp pointer to the @p SDCDriver object
* @return The card state.
* @retval FALSE card not inserted.
* @retval TRUE card inserted.
*
* @api
*/
#define sdcIsCardInserted(sdcp) (sdc_lld_is_card_inserted(sdcp))
/**
* @brief Returns the write protect status.
* @note This macro wraps a low level function named
* @p sdc_lld_is_write_protected(), this function must be
* provided by the application because it is not part of the
* SDC driver.
*
* @param[in] sdcp pointer to the @p SDCDriver object
* @return The card state.
* @retval FALSE not write protected.
* @retval TRUE write protected.
*
* @api
*/
#define sdcIsWriteProtected(sdcp) (sdc_lld_is_write_protected(sdcp))
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void sdcInit(void);
void sdcObjectInit(SDCDriver *sdcp);
void sdcStart(SDCDriver *sdcp, const SDCConfig *config);
void sdcStop(SDCDriver *sdcp);
bool_t sdcConnect(SDCDriver *sdcp);
bool_t sdcDisconnect(SDCDriver *sdcp);
bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk,
uint8_t *buffer, uint32_t n);
bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk,
const uint8_t *buffer, uint32_t n);
sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp);
bool_t sdcSync(SDCDriver *sdcp);
bool_t sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip);
bool_t sdcErase(SDCDriver *mmcp, uint32_t startblk, uint32_t endblk);
bool_t _sdc_wait_for_transfer_state(SDCDriver *sdcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SDC */
#endif /* _SDC_H_ */
/** @} */

View File

@ -0,0 +1,323 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file serial.h
* @brief Serial Driver macros and structures.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_H_
#define _SERIAL_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Serial status flags
* @{
*/
#define SD_PARITY_ERROR 32 /**< @brief Parity error happened. */
#define SD_FRAMING_ERROR 64 /**< @brief Framing error happened. */
#define SD_OVERRUN_ERROR 128 /**< @brief Overflow happened. */
#define SD_NOISE_ERROR 256 /**< @brief Noise on the line. */
#define SD_BREAK_DETECTED 512 /**< @brief Break detected. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Serial configuration options
* @{
*/
/**
* @brief Default bit rate.
* @details Configuration parameter, this is the baud rate selected for the
* default configuration.
*/
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
#define SERIAL_DEFAULT_BITRATE 38400
#endif
/**
* @brief Serial buffers size.
* @details Configuration parameter, you can change the depth of the queue
* buffers depending on the requirements of your application.
* @note The default is 16 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_BUFFERS_SIZE 16
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !CH_USE_QUEUES && !CH_USE_EVENTS
#error "Serial Driver requires CH_USE_QUEUES and CH_USE_EVENTS"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SD_UNINIT = 0, /**< Not initialized. */
SD_STOP = 1, /**< Stopped. */
SD_READY = 2 /**< Ready. */
} sdstate_t;
/**
* @brief Structure representing a serial driver.
*/
typedef struct SerialDriver SerialDriver;
#include "serial_lld.h"
/**
* @brief @p SerialDriver specific methods.
*/
#define _serial_driver_methods \
_base_asynchronous_channel_methods
/**
* @extends BaseAsynchronousChannelVMT
*
* @brief @p SerialDriver virtual methods table.
*/
struct SerialDriverVMT {
_serial_driver_methods
};
/**
* @extends BaseAsynchronousChannel
*
* @brief Full duplex serial driver class.
* @details This class extends @p BaseAsynchronousChannel by adding physical
* I/O queues.
*/
struct SerialDriver {
/** @brief Virtual Methods Table.*/
const struct SerialDriverVMT *vmt;
_serial_driver_data
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Direct output check on a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* checks directly the output queue. This is faster but cannot
* be used to check different channels implementations.
*
* @deprecated
*
* @api
*/
#define sdPutWouldBlock(sdp) chOQIsFullI(&(sdp)->oqueue)
/**
* @brief Direct input check on a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* checks directly the input queue. This is faster but cannot
* be used to check different channels implementations.
*
* @deprecated
*
* @api
*/
#define sdGetWouldBlock(sdp) chIQIsEmptyI(&(sdp)->iqueue)
/**
* @brief Direct write to a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* writes directly on the output queue. This is faster but cannot
* be used to write to different channels implementations.
*
* @see chnPutTimeout()
*
* @api
*/
#define sdPut(sdp, b) chOQPut(&(sdp)->oqueue, b)
/**
* @brief Direct write to a @p SerialDriver with timeout specification.
* @note This function bypasses the indirect access to the channel and
* writes directly on the output queue. This is faster but cannot
* be used to write to different channels implementations.
*
* @see chnPutTimeout()
*
* @api
*/
#define sdPutTimeout(sdp, b, t) chOQPutTimeout(&(sdp)->oqueue, b, t)
/**
* @brief Direct read from a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
*
* @see chnGetTimeout()
*
* @api
*/
#define sdGet(sdp) chIQGet(&(sdp)->iqueue)
/**
* @brief Direct read from a @p SerialDriver with timeout specification.
* @note This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
*
* @see chnGetTimeout()
*
* @api
*/
#define sdGetTimeout(sdp, t) chIQGetTimeout(&(sdp)->iqueue, t)
/**
* @brief Direct blocking write to a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write from different channels implementations.
*
* @see chnWrite()
*
* @api
*/
#define sdWrite(sdp, b, n) \
chOQWriteTimeout(&(sdp)->oqueue, b, n, TIME_INFINITE)
/**
* @brief Direct blocking write to a @p SerialDriver with timeout
* specification.
* @note This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write to different channels implementations.
*
* @see chnWriteTimeout()
*
* @api
*/
#define sdWriteTimeout(sdp, b, n, t) \
chOQWriteTimeout(&(sdp)->oqueue, b, n, t)
/**
* @brief Direct non-blocking write to a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write to different channels implementations.
*
* @see chnWriteTimeout()
*
* @api
*/
#define sdAsynchronousWrite(sdp, b, n) \
chOQWriteTimeout(&(sdp)->oqueue, b, n, TIME_IMMEDIATE)
/**
* @brief Direct blocking read from a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
*
* @see chnRead()
*
* @api
*/
#define sdRead(sdp, b, n) \
chIQReadTimeout(&(sdp)->iqueue, b, n, TIME_INFINITE)
/**
* @brief Direct blocking read from a @p SerialDriver with timeout
* specification.
* @note This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
*
* @see chnReadTimeout()
*
* @api
*/
#define sdReadTimeout(sdp, b, n, t) \
chIQReadTimeout(&(sdp)->iqueue, b, n, t)
/**
* @brief Direct non-blocking read from a @p SerialDriver.
* @note This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
*
* @see chnReadTimeout()
*
* @api
*/
#define sdAsynchronousRead(sdp, b, n) \
chIQReadTimeout(&(sdp)->iqueue, b, n, TIME_IMMEDIATE)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void sdInit(void);
void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify);
void sdStart(SerialDriver *sdp, const SerialConfig *config);
void sdStop(SerialDriver *sdp);
void sdIncomingDataI(SerialDriver *sdp, uint8_t b);
msg_t sdRequestDataI(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_H_ */
/** @} */

View File

@ -0,0 +1,241 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file serial_usb.h
* @brief Serial over USB Driver macros and structures.
*
* @addtogroup SERIAL_USB
* @{
*/
#ifndef _SERIAL_USB_H_
#define _SERIAL_USB_H_
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name CDC specific messages.
* @{
*/
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
/** @} */
/**
* @name Line Control bit definitions.
* @{
*/
#define LC_STOP_1 0
#define LC_STOP_1P5 1
#define LC_STOP_2 2
#define LC_PARITY_NONE 0
#define LC_PARITY_ODD 1
#define LC_PARITY_EVEN 2
#define LC_PARITY_MARK 3
#define LC_PARITY_SPACE 4
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SERIAL_USB configuration options
* @{
*/
/**
* @brief Serial over USB buffers size.
* @details Configuration parameter, the buffer size must be a multiple of
* the USB data endpoint maximum packet size.
* @note The default is 256 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_USB_BUFFERS_SIZE 256
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !HAL_USE_USB || !CH_USE_QUEUES || !CH_USE_EVENTS
#error "Serial over USB Driver requires HAL_USE_USB, CH_USE_QUEUES, "
"CH_USE_EVENTS"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of Line Coding structure.
*/
typedef struct {
uint8_t dwDTERate[4];
uint8_t bCharFormat;
uint8_t bParityType;
uint8_t bDataBits;
} cdc_linecoding_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SDU_UNINIT = 0, /**< Not initialized. */
SDU_STOP = 1, /**< Stopped. */
SDU_READY = 2 /**< Ready. */
} sdustate_t;
/**
* @brief Structure representing a serial over USB driver.
*/
typedef struct SerialUSBDriver SerialUSBDriver;
/**
* @brief Serial over USB Driver configuration structure.
* @details An instance of this structure must be passed to @p sduStart()
* in order to configure and start the driver operations.
*/
typedef struct {
/**
* @brief USB driver to use.
*/
USBDriver *usbp;
/**
* @brief Bulk IN endpoint used for outgoing data transfer.
*/
usbep_t bulk_in;
/**
* @brief Bulk OUT endpoint used for incoming data transfer.
*/
usbep_t bulk_out;
/**
* @brief Interrupt IN endpoint used for notifications.
*/
usbep_t int_in;
} SerialUSBConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_usb_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdustate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue oqueue; \
/* Input buffer.*/ \
uint8_t ib[SERIAL_USB_BUFFERS_SIZE]; \
/* Output buffer.*/ \
uint8_t ob[SERIAL_USB_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Current configuration data.*/ \
const SerialUSBConfig *config;
/**
* @brief @p SerialUSBDriver specific methods.
*/
#define _serial_usb_driver_methods \
_base_asynchronous_channel_methods
/**
* @extends BaseAsynchronousChannelVMT
*
* @brief @p SerialDriver virtual methods table.
*/
struct SerialUSBDriverVMT {
_serial_usb_driver_methods
};
/**
* @extends BaseAsynchronousChannel
*
* @brief Full duplex serial driver class.
* @details This class extends @p BaseAsynchronousChannel by adding physical
* I/O queues.
*/
struct SerialUSBDriver {
/** @brief Virtual Methods Table.*/
const struct SerialUSBDriverVMT *vmt;
_serial_usb_driver_data
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void sduInit(void);
void sduObjectInit(SerialUSBDriver *sdp);
void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config);
void sduStop(SerialUSBDriver *sdup);
void sduConfigureHookI(SerialUSBDriver *sdup);
bool_t sduRequestsHook(USBDriver *usbp);
void sduDataTransmitted(USBDriver *usbp, usbep_t ep);
void sduDataReceived(USBDriver *usbp, usbep_t ep);
void sduInterruptTransmitted(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL_USB */
#endif /* _SERIAL_USB_H_ */
/** @} */

View File

@ -0,0 +1,331 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file spi.h
* @brief SPI Driver macros and structures.
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_H_
#define _SPI_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SPI configuration options
* @{
*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if SPI_USE_MUTUAL_EXCLUSION && !CH_USE_MUTEXES && !CH_USE_SEMAPHORES
#error "SPI_USE_MUTUAL_EXCLUSION requires CH_USE_MUTEXES and/or CH_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SPI_UNINIT = 0, /**< Not initialized. */
SPI_STOP = 1, /**< Stopped. */
SPI_READY = 2, /**< Ready. */
SPI_ACTIVE = 3, /**< Exchanging data. */
SPI_COMPLETE = 4 /**< Asynchronous operation complete. */
} spistate_t;
#include "spi_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @iclass
*/
#define spiSelectI(spip) { \
spi_lld_select(spip); \
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @iclass
*/
#define spiUnselectI(spip) { \
spi_lld_unselect(spip); \
}
/**
* @brief Ignores data on the SPI bus.
* @details This asynchronous function starts the transmission of a series of
* idle words on the SPI bus and ignores the received data.
* @pre A slave must have been selected using @p spiSelect() or
* @p spiSelectI().
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @iclass
*/
#define spiStartIgnoreI(spip, n) { \
(spip)->state = SPI_ACTIVE; \
spi_lld_ignore(spip, n); \
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @pre A slave must have been selected using @p spiSelect() or
* @p spiSelectI().
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_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
*
* @iclass
*/
#define spiStartExchangeI(spip, n, txbuf, rxbuf) { \
(spip)->state = SPI_ACTIVE; \
spi_lld_exchange(spip, n, txbuf, rxbuf); \
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @pre A slave must have been selected using @p spiSelect() or
* @p spiSelectI().
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_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
*
* @iclass
*/
#define spiStartSendI(spip, n, txbuf) { \
(spip)->state = SPI_ACTIVE; \
spi_lld_send(spip, n, txbuf); \
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @pre A slave must have been selected using @p spiSelect() or
* @p spiSelectI().
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_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
*
* @iclass
*/
#define spiStartReceiveI(spip, n, rxbuf) { \
(spip)->state = SPI_ACTIVE; \
spi_lld_receive(spip, n, rxbuf); \
}
/**
* @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.
* @note This API is implemented as a macro in order to minimize latency.
*
* @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.
*/
#define spiPolledExchange(spip, frame) spi_lld_polled_exchange(spip, frame)
/** @} */
/**
* @name Low Level driver helper macros
* @{
*/
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waits for operation completion.
* @details This function waits for the driver to complete the current
* operation.
* @pre An operation must be running while the function is invoked.
* @note No more than one thread can wait on a SPI driver using
* this function.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
#define _spi_wait_s(spip) { \
chDbgAssert((spip)->thread == NULL, \
"_spi_wait(), #1", "already waiting"); \
(spip)->thread = chThdSelf(); \
chSchGoSleepS(THD_STATE_SUSPENDED); \
}
/**
* @brief Wakes up the waiting thread.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
#define _spi_wakeup_isr(spip) { \
chSysLockFromIsr(); \
if ((spip)->thread != NULL) { \
Thread *tp = (spip)->thread; \
(spip)->thread = NULL; \
tp->p_u.rdymsg = RDY_OK; \
chSchReadyI(tp); \
} \
chSysUnlockFromIsr(); \
}
#else /* !SPI_USE_WAIT */
#define _spi_wait_s(spip)
#define _spi_wakeup_isr(spip)
#endif /* !SPI_USE_WAIT */
/**
* @brief Common ISR code.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
#define _spi_isr_code(spip) { \
if ((spip)->config->end_cb) { \
(spip)->state = SPI_COMPLETE; \
(spip)->config->end_cb(spip); \
if ((spip)->state == SPI_COMPLETE) \
(spip)->state = SPI_READY; \
} \
else \
(spip)->state = SPI_READY; \
_spi_wakeup_isr(spip); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void spiInit(void);
void spiObjectInit(SPIDriver *spip);
void spiStart(SPIDriver *spip, const SPIConfig *config);
void spiStop(SPIDriver *spip);
void spiSelect(SPIDriver *spip);
void spiUnselect(SPIDriver *spip);
void spiStartIgnore(SPIDriver *spip, size_t n);
void spiStartExchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
#if SPI_USE_WAIT
void spiIgnore(SPIDriver *spip, size_t n);
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION
void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(SPIDriver *spip);
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SPI */
#endif /* _SPI_H_ */
/** @} */

View File

@ -0,0 +1,125 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file tm.h
* @brief Time Measurement driver header.
*
* @addtogroup TM
* @{
*/
#ifndef _TM_H_
#define _TM_H_
#if HAL_USE_TM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a Time Measurement object.
* @note Start/stop of measurements is performed through the function
* pointers in order to avoid inlining of those functions which
* could compromise measurement accuracy.
* @note The maximum measurable time period depends on the implementation
* of the realtime counter in the HAL driver.
* @note The measurement is not 100% cycle-accurate, it can be in excess
* of few cycles depending on the compiler and target architecture.
* @note Interrupts can affect measurement if the measurement is performed
* with interrupts enabled.
*/
typedef struct TimeMeasurement TimeMeasurement;
/**
* @brief Time Measurement structure.
*/
struct TimeMeasurement {
void (*start)(TimeMeasurement *tmp); /**< @brief Starts a measurement. */
void (*stop)(TimeMeasurement *tmp); /**< @brief Stops a measurement. */
halrtcnt_t last; /**< @brief Last measurement. */
halrtcnt_t worst; /**< @brief Worst measurement. */
halrtcnt_t best; /**< @brief Best measurement. */
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Starts a measurement.
* @pre The @p TimeMeasurement must be initialized.
* @note This function can be invoked in any context.
*
* @param[in,out] tmp pointer to a @p TimeMeasurement structure
*
* @special
*/
#define tmStartMeasurement(tmp) (tmp)->start(tmp)
/**
* @brief Stops a measurement.
* @pre The @p TimeMeasurement must be initialized.
* @note This function can be invoked in any context.
*
* @param[in,out] tmp pointer to a @p TimeMeasurement structure
*
* @special
*/
#define tmStopMeasurement(tmp) (tmp)->stop(tmp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void tmInit(void);
void tmObjectInit(TimeMeasurement *tmp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_TM */
#endif /* _TM_H_ */
/** @} */

View File

@ -0,0 +1,129 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file uart.h
* @brief UART Driver macros and structures.
*
* @addtogroup UART
* @{
*/
#ifndef _UART_H_
#define _UART_H_
#if HAL_USE_UART || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name UART status flags
* @{
*/
#define UART_NO_ERROR 0 /**< @brief No pending conditions. */
#define UART_PARITY_ERROR 4 /**< @brief Parity error happened. */
#define UART_FRAMING_ERROR 8 /**< @brief Framing error happened. */
#define UART_OVERRUN_ERROR 16 /**< @brief Overflow happened. */
#define UART_NOISE_ERROR 32 /**< @brief Noise on the line. */
#define UART_BREAK_DETECTED 64 /**< @brief Break detected. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
UART_UNINIT = 0, /**< Not initialized. */
UART_STOP = 1, /**< Stopped. */
UART_READY = 2 /**< Ready. */
} uartstate_t;
/**
* @brief Transmitter state machine states.
*/
typedef enum {
UART_TX_IDLE = 0, /**< Not transmitting. */
UART_TX_ACTIVE = 1, /**< Transmitting. */
UART_TX_COMPLETE = 2 /**< Buffer complete. */
} uarttxstate_t;
/**
* @brief Receiver state machine states.
*/
typedef enum {
UART_RX_IDLE = 0, /**< Not receiving. */
UART_RX_ACTIVE = 1, /**< Receiving. */
UART_RX_COMPLETE = 2 /**< Buffer complete. */
} uartrxstate_t;
#include "uart_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void uartInit(void);
void uartObjectInit(UARTDriver *uartp);
void uartStart(UARTDriver *uartp, const UARTConfig *config);
void uartStop(UARTDriver *uartp);
void uartStartSend(UARTDriver *uartp, size_t n, const void *txbuf);
void uartStartSendI(UARTDriver *uartp, size_t n, const void *txbuf);
size_t uartStopSend(UARTDriver *uartp);
size_t uartStopSendI(UARTDriver *uartp);
void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf);
void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf);
size_t uartStopReceive(UARTDriver *uartp);
size_t uartStopReceiveI(UARTDriver *uartp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_UART */
#endif /* _UART_H_ */
/** @} */

View File

@ -0,0 +1,585 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file usb.h
* @brief USB Driver macros and structures.
*
* @addtogroup USB
* @{
*/
#ifndef _USB_H_
#define _USB_H_
#if HAL_USE_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define USB_RTYPE_DIR_MASK 0x80
#define USB_RTYPE_DIR_HOST2DEV 0x00
#define USB_RTYPE_DIR_DEV2HOST 0x80
#define USB_RTYPE_TYPE_MASK 0x60
#define USB_RTYPE_TYPE_STD 0x00
#define USB_RTYPE_TYPE_CLASS 0x20
#define USB_RTYPE_TYPE_VENDOR 0x40
#define USB_RTYPE_TYPE_RESERVED 0x60
#define USB_RTYPE_RECIPIENT_MASK 0x1F
#define USB_RTYPE_RECIPIENT_DEVICE 0x00
#define USB_RTYPE_RECIPIENT_INTERFACE 0x01
#define USB_RTYPE_RECIPIENT_ENDPOINT 0x02
#define USB_RTYPE_RECIPIENT_OTHER 0x03
#define USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
#define USB_REQ_SET_FEATURE 3
#define USB_REQ_SET_ADDRESS 5
#define USB_REQ_GET_DESCRIPTOR 6
#define USB_REQ_SET_DESCRIPTOR 7
#define USB_REQ_GET_CONFIGURATION 8
#define USB_REQ_SET_CONFIGURATION 9
#define USB_REQ_GET_INTERFACE 10
#define USB_REQ_SET_INTERFACE 11
#define USB_REQ_SYNCH_FRAME 12
#define USB_DESCRIPTOR_DEVICE 1
#define USB_DESCRIPTOR_CONFIGURATION 2
#define USB_DESCRIPTOR_STRING 3
#define USB_DESCRIPTOR_INTERFACE 4
#define USB_DESCRIPTOR_ENDPOINT 5
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 6
#define USB_DESCRIPTOR_OTHER_SPEED_CFG 7
#define USB_DESCRIPTOR_INTERFACE_POWER 8
#define USB_DESCRIPTOR_INTERFACE_ASSOCIATION 11
#define USB_FEATURE_ENDPOINT_HALT 0
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1
#define USB_FEATURE_TEST_MODE 2
#define USB_EARLY_SET_ADDRESS 0
#define USB_LATE_SET_ADDRESS 1
#define USB_EP0_STATUS_STAGE_SW 0
#define USB_EP0_STATUS_STAGE_HW 1
#define USB_SET_ADDRESS_ACK_SW 0
#define USB_SET_ADDRESS_ACK_HW 1
/**
* @name Helper macros for USB descriptors
* @{
*/
/**
* @brief Helper macro for index values into descriptor strings.
*/
#define USB_DESC_INDEX(i) ((uint8_t)(i))
/**
* @brief Helper macro for byte values into descriptor strings.
*/
#define USB_DESC_BYTE(b) ((uint8_t)(b))
/**
* @brief Helper macro for word values into descriptor strings.
*/
#define USB_DESC_WORD(w) \
(uint8_t)((w) & 255), \
(uint8_t)(((w) >> 8) & 255)
/**
* @brief Helper macro for BCD values into descriptor strings.
*/
#define USB_DESC_BCD(bcd) \
(uint8_t)((bcd) & 255), \
(uint8_t)(((bcd) >> 8) & 255)
/**
* @brief Device Descriptor helper macro.
*/
#define USB_DESC_DEVICE(bcdUSB, bDeviceClass, bDeviceSubClass, \
bDeviceProtocol, bMaxPacketSize, idVendor, \
idProduct, bcdDevice, iManufacturer, \
iProduct, iSerialNumber, bNumConfigurations) \
USB_DESC_BYTE(18), \
USB_DESC_BYTE(USB_DESCRIPTOR_DEVICE), \
USB_DESC_BCD(bcdUSB), \
USB_DESC_BYTE(bDeviceClass), \
USB_DESC_BYTE(bDeviceSubClass), \
USB_DESC_BYTE(bDeviceProtocol), \
USB_DESC_BYTE(bMaxPacketSize), \
USB_DESC_WORD(idVendor), \
USB_DESC_WORD(idProduct), \
USB_DESC_BCD(bcdDevice), \
USB_DESC_INDEX(iManufacturer), \
USB_DESC_INDEX(iProduct), \
USB_DESC_INDEX(iSerialNumber), \
USB_DESC_BYTE(bNumConfigurations)
/**
* @brief Configuration Descriptor helper macro.
*/
#define USB_DESC_CONFIGURATION(wTotalLength, bNumInterfaces, \
bConfigurationValue, iConfiguration, \
bmAttributes, bMaxPower) \
USB_DESC_BYTE(9), \
USB_DESC_BYTE(USB_DESCRIPTOR_CONFIGURATION), \
USB_DESC_WORD(wTotalLength), \
USB_DESC_BYTE(bNumInterfaces), \
USB_DESC_BYTE(bConfigurationValue), \
USB_DESC_INDEX(iConfiguration), \
USB_DESC_BYTE(bmAttributes), \
USB_DESC_BYTE(bMaxPower)
/**
* @brief Interface Descriptor helper macro.
*/
#define USB_DESC_INTERFACE(bInterfaceNumber, bAlternateSetting, \
bNumEndpoints, bInterfaceClass, \
bInterfaceSubClass, bInterfaceProtocol, \
iInterface) \
USB_DESC_BYTE(9), \
USB_DESC_BYTE(USB_DESCRIPTOR_INTERFACE), \
USB_DESC_BYTE(bInterfaceNumber), \
USB_DESC_BYTE(bAlternateSetting), \
USB_DESC_BYTE(bNumEndpoints), \
USB_DESC_BYTE(bInterfaceClass), \
USB_DESC_BYTE(bInterfaceSubClass), \
USB_DESC_BYTE(bInterfaceProtocol), \
USB_DESC_INDEX(iInterface)
/**
* @brief Interface Association Descriptor helper macro.
*/
#define USB_DESC_INTERFACE_ASSOCIATION(bFirstInterface, \
bInterfaceCount, bFunctionClass, \
bFunctionSubClass, bFunctionProcotol, \
iInterface) \
USB_DESC_BYTE(8), \
USB_DESC_BYTE(USB_DESCRIPTOR_INTERFACE_ASSOCIATION), \
USB_DESC_BYTE(bFirstInterface), \
USB_DESC_BYTE(bInterfaceCount), \
USB_DESC_BYTE(bFunctionClass), \
USB_DESC_BYTE(bFunctionSubClass), \
USB_DESC_BYTE(bFunctionProcotol), \
USB_DESC_INDEX(iInterface)
/**
* @brief Endpoint Descriptor helper macro.
*/
#define USB_DESC_ENDPOINT(bEndpointAddress, bmAttributes, wMaxPacketSize, \
bInterval) \
USB_DESC_BYTE(7), \
USB_DESC_BYTE(USB_DESCRIPTOR_ENDPOINT), \
USB_DESC_BYTE(bEndpointAddress), \
USB_DESC_BYTE(bmAttributes), \
USB_DESC_WORD(wMaxPacketSize), \
USB_DESC_BYTE(bInterval)
/** @} */
/**
* @name Endpoint types and settings
* @{
*/
#define USB_EP_MODE_TYPE 0x0003 /**< Endpoint type mask. */
#define USB_EP_MODE_TYPE_CTRL 0x0000 /**< Control endpoint. */
#define USB_EP_MODE_TYPE_ISOC 0x0001 /**< Isochronous endpoint. */
#define USB_EP_MODE_TYPE_BULK 0x0002 /**< Bulk endpoint. */
#define USB_EP_MODE_TYPE_INTR 0x0003 /**< Interrupt endpoint. */
#define USB_EP_MODE_LINEAR_BUFFER 0x0000 /**< Linear buffer mode. */
#define USB_EP_MODE_QUEUE_BUFFER 0x0010 /**< Queue buffer mode. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an USB driver.
*/
typedef struct USBDriver USBDriver;
/**
* @brief Type of an endpoint identifier.
*/
typedef uint8_t usbep_t;
/**
* @brief Type of a driver state machine possible states.
*/
typedef enum {
USB_UNINIT = 0, /**< Not initialized. */
USB_STOP = 1, /**< Stopped. */
USB_READY = 2, /**< Ready, after bus reset. */
USB_SELECTED = 3, /**< Address assigned. */
USB_ACTIVE = 4 /**< Active, configuration selected.*/
} usbstate_t;
/**
* @brief Type of an endpoint status.
*/
typedef enum {
EP_STATUS_DISABLED = 0, /**< Endpoint not active. */
EP_STATUS_STALLED = 1, /**< Endpoint opened but stalled. */
EP_STATUS_ACTIVE = 2 /**< Active endpoint. */
} usbepstatus_t;
/**
* @brief Type of an endpoint zero state machine states.
*/
typedef enum {
USB_EP0_WAITING_SETUP, /**< Waiting for SETUP data. */
USB_EP0_TX, /**< Transmitting. */
USB_EP0_WAITING_TX0, /**< Waiting transmit 0. */
USB_EP0_WAITING_STS, /**< Waiting status. */
USB_EP0_RX, /**< Receiving. */
USB_EP0_SENDING_STS, /**< Sending status. */
USB_EP0_ERROR /**< Error, EP0 stalled. */
} usbep0state_t;
/**
* @brief Type of an enumeration of the possible USB events.
*/
typedef enum {
USB_EVENT_RESET = 0, /**< Driver has been reset by host. */
USB_EVENT_ADDRESS = 1, /**< Address assigned. */
USB_EVENT_CONFIGURED = 2, /**< Configuration selected. */
USB_EVENT_SUSPEND = 3, /**< Entering suspend mode. */
USB_EVENT_WAKEUP = 4, /**< Leaving suspend mode. */
USB_EVENT_STALLED = 5 /**< Endpoint 0 error, stalled. */
} usbevent_t;
/**
* @brief Type of an USB descriptor.
*/
typedef struct {
/**
* @brief Descriptor size in unicode characters.
*/
size_t ud_size;
/**
* @brief Pointer to the descriptor.
*/
const uint8_t *ud_string;
} USBDescriptor;
/**
* @brief Type of an USB generic notification callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
*/
typedef void (*usbcallback_t)(USBDriver *usbp);
/**
* @brief Type of an USB endpoint callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @param[in] ep endpoint number
*/
typedef void (*usbepcallback_t)(USBDriver *usbp, usbep_t ep);
/**
* @brief Type of an USB event notification callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @param[in] event event type
*/
typedef void (*usbeventcb_t)(USBDriver *usbp, usbevent_t event);
/**
* @brief Type of a requests handler callback.
* @details The request is encoded in the @p usb_setup buffer.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @return The request handling exit code.
* @retval FALSE Request not recognized by the handler.
* @retval TRUE Request handled.
*/
typedef bool_t (*usbreqhandler_t)(USBDriver *usbp);
/**
* @brief Type of an USB descriptor-retrieving callback.
*/
typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
uint8_t dtype,
uint8_t dindex,
uint16_t lang);
#include "usb_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the driver state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The driver state.
*
* @iclass
*/
#define usbGetDriverStateI(usbp) ((usbp)->state)
/**
* @brief Fetches a 16 bits word value from an USB message.
*
* @param[in] p pointer to the 16 bits word
*
* @notapi
*/
#define usbFetchWord(p) ((uint16_t)*(p) | ((uint16_t)*((p) + 1) << 8))
/**
* @brief Connects the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbConnectBus(usbp) usb_lld_connect_bus(usbp)
/**
* @brief Disconnect the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbDisconnectBus(usbp) usb_lld_disconnect_bus(usbp)
/**
* @brief Returns the current frame number.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The current frame number.
*
* @api
*/
#define usbGetFrameNumber(usbp) usb_lld_get_frame_number(usbp)
/**
* @brief Returns the status of an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The operation status.
* @retval FALSE Endpoint ready.
* @retval TRUE Endpoint transmitting.
*
* @iclass
*/
#define usbGetTransmitStatusI(usbp, ep) ((usbp)->transmitting & (1 << (ep)))
/**
* @brief Returns the status of an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The operation status.
* @retval FALSE Endpoint ready.
* @retval TRUE Endpoint receiving.
*
* @iclass
*/
#define usbGetReceiveStatusI(usbp, ep) ((usbp)->receiving & (1 << (ep)))
/**
* @brief Returns the exact size of a receive transaction.
* @details The received size can be different from the size specified in
* @p usbStartReceiveI() because the last packet could have a size
* different from the expected one.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return Received data size.
*
* @iclass
*/
#define usbGetReceiveTransactionSizeI(usbp, ep) \
usb_lld_get_transaction_size(usbp, ep)
/**
* @brief Request transfer setup.
* @details This macro is used by the request handling callbacks in order to
* prepare a transaction over the endpoint zero.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] buf pointer to a buffer for the transaction data
* @param[in] n number of bytes to be transferred
* @param[in] endcb callback to be invoked after the transfer or @p NULL
*
* @api
*/
#define usbSetupTransfer(usbp, buf, n, endcb) { \
(usbp)->ep0next = (buf); \
(usbp)->ep0n = (n); \
(usbp)->ep0endcb = (endcb); \
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @note This function can be invoked both in thread and IRQ context.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @special
*/
#define usbReadSetup(usbp, ep, buf) usb_lld_read_setup(usbp, ep, buf)
/** @} */
/**
* @name Low Level driver helper macros
* @{
*/
/**
* @brief Common ISR code, usb event callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] evt USB event code
*
* @notapi
*/
#define _usb_isr_invoke_event_cb(usbp, evt) { \
if (((usbp)->config->event_cb) != NULL) \
(usbp)->config->event_cb(usbp, evt); \
}
/**
* @brief Common ISR code, SOF callback.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
#define _usb_isr_invoke_sof_cb(usbp) { \
if (((usbp)->config->sof_cb) != NULL) \
(usbp)->config->sof_cb(usbp); \
}
/**
* @brief Common ISR code, setup packet callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_setup_cb(usbp, ep) { \
(usbp)->epc[ep]->setup_cb(usbp, ep); \
}
/**
* @brief Common ISR code, IN endpoint callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_in_cb(usbp, ep) { \
(usbp)->transmitting &= ~(1 << (ep)); \
(usbp)->epc[ep]->in_cb(usbp, ep); \
}
/**
* @brief Common ISR code, OUT endpoint event.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_out_cb(usbp, ep) { \
(usbp)->receiving &= ~(1 << (ep)); \
(usbp)->epc[ep]->out_cb(usbp, ep); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void usbInit(void);
void usbObjectInit(USBDriver *usbp);
void usbStart(USBDriver *usbp, const USBConfig *config);
void usbStop(USBDriver *usbp);
void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp);
void usbDisableEndpointsI(USBDriver *usbp);
void usbReadSetupI(USBDriver *usbp, usbep_t ep, uint8_t *buf);
void usbPrepareReceive(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n);
void usbPrepareTransmit(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n);
void usbPrepareQueuedReceive(USBDriver *usbp, usbep_t ep,
InputQueue *iqp, size_t n);
void usbPrepareQueuedTransmit(USBDriver *usbp, usbep_t ep,
OutputQueue *oqp, size_t n);
bool_t usbStartReceiveI(USBDriver *usbp, usbep_t ep);
bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep);
bool_t usbStallReceiveI(USBDriver *usbp, usbep_t ep);
bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep);
void _usb_reset(USBDriver *usbp);
void _usb_ep0setup(USBDriver *usbp, usbep_t ep);
void _usb_ep0in(USBDriver *usbp, usbep_t ep);
void _usb_ep0out(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_USB */
#endif /* _USB_H_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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;
}

View 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

View 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_ */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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))
;
}
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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(&ETHD1.rdsem, 0);
#if MAC_USE_EVENTS
chEvtBroadcastI(&ETHD1.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(&ETHD1.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(&ETHD1);
/*
* Associated PHY initialization.
*/
miiReset(&ETHD1);
/*
* 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(&ETHD1, MII_PHYSID1) != (PHY_ID >> 16)) ||
((miiGet(&ETHD1, 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 */
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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
*/

View 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

View 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 */
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View 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 */
/** @} */

View 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_ */
/** @} */

View File

@ -0,0 +1,57 @@
/*
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 AVR/hal_lld.c
* @brief AVR HAL subsystem low level driver code.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
}
/** @} */

View File

@ -0,0 +1,72 @@
/*
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 AVR/hal_lld.h
* @brief AVR HAL subsystem low level driver header.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Defines the support for realtime counters in the HAL.
*/
#define HAL_IMPLEMENTS_COUNTERS FALSE
/**
* @brief Platform name.
*/
#define PLATFORM_NAME "ATmega128"
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void hal_lld_init(void);
#ifdef __cplusplus
}
#endif
#endif /* _HAL_LLD_H_ */
/** @} */

View File

@ -0,0 +1,289 @@
/*
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 AVR/i2c_lld.c
* @brief AVR I2C subsystem low level driver source.
*
* @addtogroup I2C
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief I2C driver identifier.*/
#if USE_AVR_I2C || defined(__DOXYGEN__)
I2CDriver I2CD;
#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(); \
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if USE_AVR_I2C || defined(__DOXYGEN__)
/**
* @brief I2C event interrupt handler.
*
* @notapi
*/
CH_IRQ_HANDLER(TWI_vect) {
CH_IRQ_PROLOGUE();
I2CDriver *i2cp = &I2CD;
switch (TWSR & 0xF8) {
case TWI_START:
case TWI_REPEAT_START:
TWDR = (i2cp->addr << 1);
if ((i2cp->txbuf == NULL) || (i2cp->txbytes == 0) || (i2cp->txidx == i2cp->txbytes)) {
TWDR |= 0x01;
}
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWIE));
break;
case TWI_MASTER_TX_ADDR_ACK:
case TWI_MASTER_TX_DATA_ACK:
if (i2cp->txidx < i2cp->txbytes) {
TWDR = i2cp->txbuf[i2cp->txidx++];
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWIE));
} else {
if (i2cp->rxbuf && i2cp->rxbytes) {
TWCR = ((1 << TWSTA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));
} else {
TWCR = ((1 << TWSTO) | (1 << TWINT) | (1 << TWEN));
wakeup_isr(i2cp, RDY_OK);
}
}
break;
case TWI_MASTER_RX_ADDR_ACK:
if (i2cp->rxidx == (i2cp->rxbytes - 1)) {
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWIE));
} else {
TWCR = ((1 << TWEA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));
}
break;
case TWI_MASTER_RX_DATA_ACK:
i2cp->rxbuf[i2cp->rxidx++] = TWDR;
if (i2cp->rxidx == (i2cp->rxbytes - 1)) {
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWIE));
} else {
TWCR = ((1 << TWEA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));
}
break;
case TWI_MASTER_RX_DATA_NACK:
i2cp->rxbuf[i2cp->rxidx] = TWDR;
TWCR = ((1 << TWSTO) | (1 << TWINT) | (1 << TWEN));
wakeup_isr(i2cp, RDY_OK);
case TWI_MASTER_TX_ADDR_NACK:
case TWI_MASTER_TX_DATA_NACK:
case TWI_MASTER_RX_ADDR_NACK:
i2cp->errors |= I2CD_ACK_FAILURE;
break;
case TWI_ARBITRATION_LOST:
i2cp->errors |= I2CD_ARBITRATION_LOST;
break;
case TWI_BUS_ERROR:
i2cp->errors |= I2CD_BUS_ERROR;
break;
default:
/* FIXME: only gets here if there are other MASTERs in the bus */
TWCR = ((1 << TWSTO) | (1 << TWINT) | (1 << TWEN));
wakeup_isr(i2cp, RDY_RESET);
}
if (i2cp->errors != I2CD_NO_ERROR) {
TWCR = ((1 << TWSTO) | (1 << TWINT) | (1 << TWEN));
wakeup_isr(i2cp, RDY_RESET);
}
CH_IRQ_EPILOGUE();
}
#endif /* USE_AVR_I2C */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level I2C driver initialization.
*
* @notapi
*/
void i2c_lld_init(void) {
i2cObjectInit(&I2CD);
}
/**
* @brief Configures and activates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
void i2c_lld_start(I2CDriver *i2cp) {
/* TODO: Test TWI without external pull-ups (use internal) */
/* Configure prescaler to 1 */
TWSR &= 0xF8;
/* Configure baudrate */
TWBR = ((F_CPU / i2cp->config->clock_speed) - 16) / 2;
}
/**
* @brief Deactivates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
void i2c_lld_stop(I2CDriver *i2cp) {
if (i2cp->state != I2C_STOP) {
/* Disable TWI subsystem and stop all operations */
TWCR &= ~(1 << TWEN);
}
}
/**
* @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 the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* @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().
* @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a
* timeout the driver must be stopped and restarted
* because the bus is in an uncertain state</b>.
*
* @notapi
*/
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
i2cp->addr = addr;
i2cp->txbuf = NULL;
i2cp->txbytes = 0;
i2cp->txidx = 0;
i2cp->rxbuf = rxbuf;
i2cp->rxbytes = rxbytes;
i2cp->rxidx = 0;
/* Send START */
TWCR = ((1 << TWSTA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));
chSysLock();
i2cp->thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
chSysUnlock();
return chThdSelf()->p_u.rdymsg;
}
/**
* @brief Transmits data via the I2C bus as master.
*
* @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 the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* @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().
* @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a
* timeout the driver must be stopped and restarted
* because the bus is in an uncertain state</b>.
*
* @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) {
i2cp->addr = addr;
i2cp->txbuf = txbuf;
i2cp->txbytes = txbytes;
i2cp->txidx = 0;
i2cp->rxbuf = rxbuf;
i2cp->rxbytes = rxbytes;
i2cp->rxidx = 0;
TWCR = ((1 << TWSTA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));
chSysLock();
i2cp->thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
chSysUnlock();
return chThdSelf()->p_u.rdymsg;
}
#endif /* HAL_USE_I2C */
/** @} */

View File

@ -0,0 +1,224 @@
/*
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 AVR/i2c_lld.h
* @brief AVR 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 START transmitted.*/
#define TWI_START 0x08
/** @brief Repeated START transmitted.*/
#define TWI_REPEAT_START 0x10
/** @brief Arbitration Lost.*/
#define TWI_ARBITRATION_LOST 0x38
/** @brief Bus errors.*/
#define TWI_BUS_ERROR 0x00
/** @brief SLA+W transmitted with ACK response.*/
#define TWI_MASTER_TX_ADDR_ACK 0x18
/** @brief SLA+W transmitted with NACK response.*/
#define TWI_MASTER_TX_ADDR_NACK 0x20
/** @brief DATA transmitted with ACK response.*/
#define TWI_MASTER_TX_DATA_ACK 0x28
/** @brief DATA transmitted with NACK response.*/
#define TWI_MASTER_TX_DATA_NACK 0x30
/** @brief SLA+R transmitted with ACK response.*/
#define TWI_MASTER_RX_ADDR_ACK 0x40
/** @brief SLA+R transmitted with NACK response.*/
#define TWI_MASTER_RX_ADDR_NACK 0x48
/** @brief DATA received with ACK response.*/
#define TWI_MASTER_RX_DATA_ACK 0x50
/** @brief DATA received with NACK response.*/
#define TWI_MASTER_RX_DATA_NACK 0x58
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C driver enable switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(USE_AVR_I2C) || defined(__DOXYGEN__)
#define USE_AVR_I2C FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing I2C address.
*/
typedef uint8_t i2caddr_t;
/**
* @brief I2C Driver condition flags type.
*/
typedef uint8_t i2cflags_t;
/**
* @brief Driver configuration structure.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Specifies the I2C clock frequency.
*/
uint32_t clock_speed;
} I2CConfig;
/**
* @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;
#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;
/**
* @brief Address of slave device.
*/
i2caddr_t addr;
/**
* @brief Pointer to the buffer with data to send.
*/
const uint8_t *txbuf;
/**
* @brief Number of bytes of data to send.
*/
size_t txbytes;
/**
* @brief Current index in buffer when sending data.
*/
size_t txidx;
/**
* @brief Pointer to the buffer to put received data.
*/
uint8_t *rxbuf;
/**
* @brief Number of bytes of data to receive.
*/
size_t rxbytes;
/**
* @brief Current index in buffer when receiving data.
*/
size_t rxidx;
};
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/*===========================================================================*/
/* 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 USE_AVR_I2C
extern I2CDriver I2CD;
#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_ */
/** @} */

View File

@ -0,0 +1,157 @@
/*
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 AVR/pal_lld.c
* @brief AVR GPIO 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 AVR GPIO ports configuration.
* @details GPIO registers initialization.
*
* @param[in] config the AVR ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
#if defined(PORTA) || defined(__DOXYGEN__)
PORTA = config->porta.out;
DDRA = config->porta.dir;
#endif
#if defined(PORTB) || defined(__DOXYGEN__)
PORTB = config->portb.out;
DDRB = config->portb.dir;
#endif
#if defined(PORTC) || defined(__DOXYGEN__)
PORTC = config->portc.out;
DDRC = config->portc.dir;
#endif
#if defined(PORTD) || defined(__DOXYGEN__)
PORTD = config->portd.out;
DDRD = config->portd.dir;
#endif
#if defined(PORTE) || defined(__DOXYGEN__)
PORTE = config->porte.out;
DDRE = config->porte.dir;
#endif
#if defined(PORTF) || defined(__DOXYGEN__)
PORTF = config->portf.out;
DDRF = config->portf.dir;
#endif
#if defined(PORTG) || defined(__DOXYGEN__)
PORTG = config->portg.out;
DDRG = config->portg.dir;
#endif
#if defined(PORTH) || defined(__DOXYGEN__)
PORTH = config->porth.out;
DDRH = config->porth.dir;
#endif
#if defined(PORTJ) || defined(__DOXYGEN__)
PORTJ = config->portj.out;
DDRJ = config->portj.dir;
#endif
#if defined(PORTK) || defined(__DOXYGEN__)
PORTK = config->portk.out;
DDRK = config->portk.dir;
#endif
#if defined(PORTL) || defined(__DOXYGEN__)
PORTL = config->portl.out;
DDRL = config->portl.dir;
#endif
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @note This function is not meant to be invoked directly by the application
* code.
* @note @p PAL_MODE_UNCONNECTED is implemented as output as recommended by
* the AVR Family User's Guide. Unconnected pads are set to input
* with pull-up by default.
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
case PAL_MODE_INPUT_ANALOG:
port->dir &= ~mask;
port->out &= ~mask;
break;
case PAL_MODE_UNCONNECTED:
case PAL_MODE_INPUT_PULLUP:
port->dir &= ~mask;
port->out |= mask;
break;
case PAL_MODE_OUTPUT_PUSHPULL:
port->dir |= mask;
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -0,0 +1,329 @@
/*
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 AVR/pal_lld.h
* @brief AVR GPIO 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 */
/*===========================================================================*/
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_OUTPUT_OPENDRAIN
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 8
/**
* @brief Whole port mask.
* @details This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFF)
/**
* @brief AVR setup registers.
*/
typedef struct {
uint8_t out;
uint8_t dir;
} avr_gpio_setup_t;
/**
* @brief AVR registers block.
* @note On some devices registers do not follow this layout on some
* ports, the ports with abnormal layout cannot be used through
* PAL driver. Example: PORT F on Mega128.
*/
typedef struct {
volatile uint8_t in;
volatile uint8_t dir;
volatile uint8_t out;
} avr_gpio_registers_t;
/**
* @brief Generic I/O ports static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
*/
typedef struct {
#if defined(PORTA) || defined(__DOXYGEN__)
avr_gpio_setup_t porta;
#endif
#if defined(PORTB) || defined(__DOXYGEN__)
avr_gpio_setup_t portb;
#endif
#if defined(PORTC) || defined(__DOXYGEN__)
avr_gpio_setup_t portc;
#endif
#if defined(PORTD) || defined(__DOXYGEN__)
avr_gpio_setup_t portd;
#endif
#if defined(PORTE) || defined(__DOXYGEN__)
avr_gpio_setup_t porte;
#endif
#if defined(PORTF) || defined(__DOXYGEN__)
avr_gpio_setup_t portf;
#endif
#if defined(PORTG) || defined(__DOXYGEN__)
avr_gpio_setup_t portg;
#endif
#if defined(PORTH) || defined(__DOXYGEN__)
avr_gpio_setup_t porth;
#endif
#if defined(PORTJ) || defined(__DOXYGEN__)
avr_gpio_setup_t portj;
#endif
#if defined(PORTK) || defined(__DOXYGEN__)
avr_gpio_setup_t portk;
#endif
#if defined(PORTL) || defined(__DOXYGEN__)
avr_gpio_setup_t portl;
#endif
} PALConfig;
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint8_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint8_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 avr_gpio_registers_t *ioportid_t;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
#if defined(PORTA) || defined(__DOXYGEN__)
/**
* @brief GPIO port A identifier.
*/
#define IOPORT1 ((volatile avr_gpio_registers_t *)&PINA)
#endif
#if defined(PORTB) || defined(__DOXYGEN__)
/**
* @brief GPIO port B identifier.
*/
#define IOPORT2 ((volatile avr_gpio_registers_t *)&PINB)
#endif
#if defined(PORTC) || defined(__DOXYGEN__)
/**
* @brief GPIO port C identifier.
*/
#define IOPORT3 ((volatile avr_gpio_registers_t *)&PINC)
#endif
#if defined(PORTD) || defined(__DOXYGEN__)
/**
* @brief GPIO port D identifier.
*/
#define IOPORT4 ((volatile avr_gpio_registers_t *)&PIND)
#endif
#if defined(PORTE) || defined(__DOXYGEN__)
/**
* @brief GPIO port E identifier.
*/
#define IOPORT5 ((volatile avr_gpio_registers_t *)&PINE)
#endif
#if defined(PORTF) || defined(__DOXYGEN__)
/**
* @brief GPIO port F identifier.
*/
#define IOPORT6 ((volatile avr_gpio_registers_t *)&PINF)
#endif
#if defined(PORTG) || defined(__DOXYGEN__)
/**
* @brief GPIO port G identifier.
*/
#define IOPORT7 ((volatile avr_gpio_registers_t *)&PING)
#endif
#if defined(PORTH) || defined(__DOXYGEN__)
/**
* @brief GPIO port H identifier.
*/
#define IOPORT8 ((volatile avr_gpio_registers_t *)&PINH)
#endif
#if defined(PORTJ) || defined(__DOXYGEN__)
/**
* @brief GPIO port J identifier.
*/
#define IOPORT9 ((volatile avr_gpio_registers_t *)&PINJ)
#endif
#if defined(PORTK) || defined(__DOXYGEN__)
/**
* @brief GPIO port K identifier.
*/
#define IOPORT10 ((volatile avr_gpio_registers_t *)&PINK)
#endif
#if defined(PORTL) || defined(__DOXYGEN__)
/**
* @brief GPIO port L identifier.
*/
#define IOPORT11 ((volatile avr_gpio_registers_t *)&PINL)
#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 the architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) ((port)->in)
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) ((port)->out)
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) ((port)->out = bits)
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @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 Sets a pad logical state to @p PAL_HIGH.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
__asm__ __volatile__ \
( \
"sbi %0,%1\n\t" \
: \
: "I" (_SFR_IO_ADDR(port->out)), \
"I" (pad) \
\
)
/**
* @brief Clears a pad logical state to @p PAL_LOW.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
__asm__ __volatile__ \
( \
"cbi %0,%1\n\t" \
: \
: "I" (_SFR_IO_ADDR(port->out)), \
"I" (pad) \
\
)
extern ROMCONST 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_ */
/** @} */

View File

@ -0,0 +1,110 @@
/*
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 AVR_DRIVERS AVR Drivers
* @details This section describes all the supported drivers on the AVR
* platform and the implementation details of the single drivers.
*
* @ingroup platforms
*/
/**
* @defgroup AVR_HAL AVR Initialization Support
* @details On the AVR platform the HAL driver is a stub and does not perform
* any platform-specific initialization, it still performs the
* initialization of the other drivers.
*
* @ingroup AVR_DRIVERS
*/
/**
* @defgroup AVR_PAL AVR PAL Support
* @details The AVR PAL driver uses the PORT peripherals.
*
* @section avr_pal_1 Supported HW resources
* - PORTA.
* - PORTB.
* - PORTC.
* - PORTD.
* - PORTE.
* - PORTF.
* - PORTG.
* .
* @section avr_pal_2 AVR PAL driver implementation features
* The AVR PAL driver implementation fully supports the following hardware
* capabilities:
* - 8 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 avr_pal_3 Supported PAL setup modes
* The AVR PAL driver supports the following I/O modes:
* - @p PAL_MODE_RESET.
* - @p PAL_MODE_UNCONNECTED.
* - @p PAL_MODE_INPUT.
* - @p PAL_MODE_INPUT_PULLUP.
* - @p PAL_MODE_INPUT_ANALOG.
* - @p PAL_MODE_OUTPUT_PUSHPULL.
* .
* Any attempt to setup an invalid mode is ignored.
*
* @section avr_pal_4 Suboptimal behavior
* The AVR PORT 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.
* - Group set+reset function is not atomic.
* - Writing on pads/groups/ports programmed as input with pull-up
* resistor changes the resistor setting because the output latch is
* used for resistor selection.
* - The PORT registers layout on some devices is not regular (it does
* not have contiguous PIN, DDR, PORT registers in this order), such
* ports cannot be accessed using the PAL driver. For example, PORT F
* on ATmega128. Verify the user manual of your device.
* .
* @ingroup AVR_DRIVERS
*/
/**
* @defgroup AVR_SERIAL AVR Serial Support
* @details The AVR Serial driver uses the USART peripherals in a
* buffered, interrupt driven, implementation.
*
* @section avr_serial_1 Supported HW resources
* The serial driver can support any of the following hardware resources:
* - USART0.
* - USART1.
* .
* @section avr_serial_2 AVR Serial driver implementation features
* - Each USART can be independently enabled and programmed.
* - Fully interrupt driven.
* .
* @ingroup AVR_DRIVERS
*/
/**
* @defgroup AVR_I2C AVR I2C Support
* @details The AVR I2C driver uses the TWI peripheral in an interrupt
* driven, implementation.
*
* @section avr_i2c Supported HW resources
* The i2c driver can support the following hardware resource:
* - I2C.
* .
* @ingroup AVR_DRIVERS
*/

View File

@ -0,0 +1,8 @@
# List of all the AVR platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/AVR/hal_lld.c \
${CHIBIOS}/os/hal/platforms/AVR/pal_lld.c \
${CHIBIOS}/os/hal/platforms/AVR/serial_lld.c \
${CHIBIOS}/os/hal/platforms/AVR/i2c_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/AVR

View File

@ -0,0 +1,360 @@
/*
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 AVR/serial_lld.c
* @brief AVR low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief USART0 serial driver identifier.
* @note The name does not follow the convention used in the other ports
* (COMn) because a name conflict with the AVR headers.
*/
#if USE_AVR_USART0 || defined(__DOXYGEN__)
SerialDriver SD1;
#endif
/**
* @brief USART1 serial driver identifier.
* @note The name does not follow the convention used in the other ports
* (COMn) because a name conflict with the AVR headers.
*/
#if USE_AVR_USART1 || defined(__DOXYGEN__)
SerialDriver SD2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Driver default configuration.
*/
static const SerialConfig default_config = {
UBRR(SERIAL_DEFAULT_BITRATE),
USART_CHAR_SIZE_8
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void set_error(uint8_t sra, SerialDriver *sdp) {
flagsmask_t sts = 0;
uint8_t dor = 0;
uint8_t upe = 0;
uint8_t fe = 0;
#if USE_AVR_USART0
if (&SD1 == sdp) {
dor = (1 << DOR0);
upe = (1 << UPE0);
fe = (1 << FE0);
}
#endif
#if USE_AVR_USART1
if (&SD2 == sdp) {
dor = (1 << DOR1);
upe = (1 << UPE1);
fe = (1 << FE1);
}
#endif
if (sra & dor)
sts |= SD_OVERRUN_ERROR;
if (sra & upe)
sts |= SD_PARITY_ERROR;
if (sra & fe)
sts |= SD_FRAMING_ERROR;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
#if USE_AVR_USART0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
UCSR0B |= (1 << UDRIE0);
}
/**
* @brief USART0 initialization.
*
* @param[in] config the architecture-dependent serial driver configuration
*/
static void usart0_init(const SerialConfig *config) {
UBRR0L = config->sc_brr;
UBRR0H = config->sc_brr >> 8;
UCSR0A = 0;
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
switch (config->sc_bits_per_char) {
case USART_CHAR_SIZE_5:
UCSR0C = 0;
break;
case USART_CHAR_SIZE_6:
UCSR0C = (1 << UCSZ00);
break;
case USART_CHAR_SIZE_7:
UCSR0C = (1 << UCSZ01);
break;
case USART_CHAR_SIZE_9:
UCSR0B |= (1 << UCSZ02);
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
break;
case USART_CHAR_SIZE_8:
default:
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
}
}
/**
* @brief USART0 de-initialization.
*/
static void usart0_deinit(void) {
UCSR0A = 0;
UCSR0B = 0;
UCSR0C = 0;
}
#endif
#if USE_AVR_USART1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
UCSR1B |= (1 << UDRIE1);
}
/**
* @brief USART1 initialization.
*
* @param[in] config the architecture-dependent serial driver configuration
*/
static void usart1_init(const SerialConfig *config) {
UBRR1L = config->sc_brr;
UBRR1H = config->sc_brr >> 8;
UCSR1A = 0;
UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
switch (config->sc_bits_per_char) {
case USART_CHAR_SIZE_5:
UCSR1C = 0;
break;
case USART_CHAR_SIZE_6:
UCSR1C = (1 << UCSZ10);
break;
case USART_CHAR_SIZE_7:
UCSR1C = (1 << UCSZ11);
break;
case USART_CHAR_SIZE_9:
UCSR1B |= (1 << UCSZ12);
UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
break;
case USART_CHAR_SIZE_8:
default:
UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
}
}
/**
* @brief USART1 de-initialization.
*/
static void usart1_deinit(void) {
UCSR1A = 0;
UCSR1B = 0;
UCSR1C = 0;
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if USE_AVR_USART0 || defined(__DOXYGEN__)
/**
* @brief USART0 RX interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(USART0_RX_vect) {
uint8_t sra;
CH_IRQ_PROLOGUE();
sra = UCSR0A;
if (sra & ((1 << DOR0) | (1 << UPE0) | (1 << FE0)))
set_error(sra, &SD1);
chSysLockFromIsr();
sdIncomingDataI(&SD1, UDR0);
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
/**
* @brief USART0 TX interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(USART0_UDRE_vect) {
msg_t b;
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
b = sdRequestDataI(&SD1);
chSysUnlockFromIsr();
if (b < Q_OK)
UCSR0B &= ~(1 << UDRIE0);
else
UDR0 = b;
CH_IRQ_EPILOGUE();
}
#endif /* USE_AVR_USART0 */
#if USE_AVR_USART1 || defined(__DOXYGEN__)
/**
* @brief USART1 RX interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(USART1_RX_vect) {
uint8_t sra;
CH_IRQ_PROLOGUE();
sra = UCSR1A;
if (sra & ((1 << DOR1) | (1 << UPE1) | (1 << FE1)))
set_error(sra, &SD2);
chSysLockFromIsr();
sdIncomingDataI(&SD2, UDR1);
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
/**
* @brief USART1 TX interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(USART1_UDRE_vect) {
msg_t b;
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
b = sdRequestDataI(&SD2);
chSysUnlockFromIsr();
if (b < Q_OK)
UCSR1B &= ~(1 << UDRIE1);
else
UDR1 = b;
CH_IRQ_EPILOGUE();
}
#endif /* USE_AVR_USART1 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if USE_AVR_USART0
sdObjectInit(&SD1, NULL, notify1);
#endif
#if USE_AVR_USART1
sdObjectInit(&SD2, NULL, notify2);
#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 USE_AVR_USART0
if (&SD1 == sdp) {
usart0_init(config);
return;
}
#endif
#if USE_AVR_USART1
if (&SD2 == sdp) {
usart1_init(config);
return;
}
#endif
}
/**
* @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 USE_AVR_USART0
if (&SD1 == sdp)
usart0_deinit();
#endif
#if USE_AVR_USART1
if (&SD2 == sdp)
usart1_deinit();
#endif
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -0,0 +1,158 @@
/*
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 AVR/serial_lld.h
* @brief AVR 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 USART0 driver enable switch.
* @details If set to @p TRUE the support for USART0 is included.
* @note The default is @p FALSE.
*/
#if !defined(USE_AVR_USART0) || defined(__DOXYGEN__)
#define USE_AVR_USART0 TRUE
#endif
/**
* @brief USART1 driver enable switch.
* @details If set to @p TRUE the support for USART1 is included.
* @note The default is @p TRUE.
*/
#if !defined(USE_AVR_USART1) || defined(__DOXYGEN__)
#define USE_AVR_USART1 TRUE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief AVR 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 Initialization value for the BRR register.
*/
uint16_t sc_brr;
/**
* @brief Number of bits per character (USART_CHAR_SIZE_5 to USART_CHAR_SIZE_9).
*/
uint8_t sc_bits_per_char;
} 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.*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Macro for baud rate computation.
* @note Make sure the final baud rate is within tolerance.
*/
#define UBRR(b) (((F_CPU / b) >> 4) - 1)
/**
* @brief Macro for baud rate computation when U2Xn == 1.
* @note Make sure the final baud rate is within tolerance.
*/
#define UBRR2x(b) (((F_CPU / b) >> 3) - 1)
/**
* @brief Macro for baud rate computation.
* @note Make sure the final baud rate is within tolerance.
* @note This version uses floating point math for greater accuracy.
*/
#define UBRR_F(b) ((((double) F_CPU / (double) b) / 16.0) - 0.5)
/**
* @brief Macro for baud rate computation when U2Xn == 1.
* @note Make sure the final baud rate is within tolerance.
* @note This version uses floating point math for greater accuracy.
*/
#define UBRR2x_F(b) ((((double) F_CPU / (double) b) / 8.0) - 0.5)
#define USART_CHAR_SIZE_5 0
#define USART_CHAR_SIZE_6 1
#define USART_CHAR_SIZE_7 2
#define USART_CHAR_SIZE_8 3
#define USART_CHAR_SIZE_9 4
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if USE_AVR_USART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if USE_AVR_USART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#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);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */

View File

@ -0,0 +1,668 @@
/****************************************************************************************************//**
* @file LPC11Uxx.h
*
*
* @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File for
* default LPC11Uxx Device Series
*
* @version V0.1
* @date 21. March 2011
*
* @note Generated with SFDGen V2.6 Build 3j (beta) on Thursday, 17.03.2011 13:19:45
*
* from CMSIS SVD File 'LPC11U1x_svd.xml' Version 0.1,
* created on Wednesday, 16.03.2011 20:30:42, last modified on Thursday, 17.03.2011 20:19:40
*
*******************************************************************************************************/
/** @addtogroup NXP
* @{
*/
/** @addtogroup LPC11Uxx
* @{
*/
#ifndef __LPC11UXX_H__
#define __LPC11UXX_H__
#ifdef __cplusplus
extern "C" {
#endif
#if defined ( __CC_ARM )
#pragma anon_unions
#endif
/* Interrupt Number Definition */
typedef enum {
// ------------------------- Cortex-M0 Processor Exceptions Numbers -----------------------------
Reset_IRQn = -15, /*!< 1 Reset Vector, invoked on Power up and warm reset */
NonMaskableInt_IRQn = -14, /*!< 2 Non maskable Interrupt, cannot be stopped or preempted */
HardFault_IRQn = -13, /*!< 3 Hard Fault, all classes of Fault */
SVCall_IRQn = -5, /*!< 11 System Service Call via SVC instruction */
DebugMonitor_IRQn = -4, /*!< 12 Debug Monitor */
PendSV_IRQn = -2, /*!< 14 Pendable request for system service */
SysTick_IRQn = -1, /*!< 15 System Tick Timer */
// --------------------------- LPC11Uxx Specific Interrupt Numbers ------------------------------
FLEX_INT0_IRQn = 0, /*!< All I/O pins can be routed to below 8 interrupts. */
FLEX_INT1_IRQn = 1,
FLEX_INT2_IRQn = 2,
FLEX_INT3_IRQn = 3,
FLEX_INT4_IRQn = 4,
FLEX_INT5_IRQn = 5,
FLEX_INT6_IRQn = 6,
FLEX_INT7_IRQn = 7,
GINT0_IRQn = 8, /*!< Grouped Interrupt 0 */
GINT1_IRQn = 9, /*!< Grouped Interrupt 1 */
Reserved0_IRQn = 10, /*!< Reserved Interrupt */
Reserved1_IRQn = 11,
Reserved2_IRQn = 12,
Reserved3_IRQn = 13,
SSP1_IRQn = 14, /*!< SSP1 Interrupt */
I2C_IRQn = 15, /*!< I2C Interrupt */
TIMER_16_0_IRQn = 16, /*!< 16-bit Timer0 Interrupt */
TIMER_16_1_IRQn = 17, /*!< 16-bit Timer1 Interrupt */
TIMER_32_0_IRQn = 18, /*!< 32-bit Timer0 Interrupt */
TIMER_32_1_IRQn = 19, /*!< 32-bit Timer1 Interrupt */
SSP0_IRQn = 20, /*!< SSP0 Interrupt */
UART_IRQn = 21, /*!< UART Interrupt */
USB_IRQn = 22, /*!< USB IRQ Interrupt */
USB_FIQn = 23, /*!< USB FIQ Interrupt */
ADC_IRQn = 24, /*!< A/D Converter Interrupt */
WDT_IRQn = 25, /*!< Watchdog timer Interrupt */
BOD_IRQn = 26, /*!< Brown Out Detect(BOD) Interrupt */
FMC_IRQn = 27, /*!< Flash Memory Controller Interrupt */
Reserved4_IRQn = 28, /*!< Reserved Interrupt */
Reserved5_IRQn = 29, /*!< Reserved Interrupt */
USBWakeup_IRQn = 30, /*!< USB wakeup Interrupt */
Reserved6_IRQn = 31, /*!< Reserved Interrupt */
} IRQn_Type;
/** @addtogroup Configuration_of_CMSIS
* @{
*/
/* Processor and Core Peripheral Section */ /* Configuration of the Cortex-M0 Processor and Core Peripherals */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 3 /*!< Number of Bits used for Priority Levels */
#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */
/** @} */ /* End of group Configuration_of_CMSIS */
#include "core_cm0.h" /*!< Cortex-M0 processor and core peripherals */
#include "system_LPC11Uxx.h" /*!< LPC11Uxx System */
/** @addtogroup Device_Peripheral_Registers
* @{
*/
// ------------------------------------------------------------------------------------------------
// ----- I2C -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x I2C-bus controller Modification date=3/16/2011 Major revision=0 Minor revision=3 (I2C)
*/
typedef struct { /*!< (@ 0x40000000) I2C Structure */
__IO uint32_t CONSET; /*!< (@ 0x40000000) I2C Control Set Register */
__I uint32_t STAT; /*!< (@ 0x40000004) I2C Status Register */
__IO uint32_t DAT; /*!< (@ 0x40000008) I2C Data Register. */
__IO uint32_t ADR0; /*!< (@ 0x4000000C) I2C Slave Address Register 0 */
__IO uint32_t SCLH; /*!< (@ 0x40000010) SCH Duty Cycle Register High Half Word */
__IO uint32_t SCLL; /*!< (@ 0x40000014) SCL Duty Cycle Register Low Half Word */
__IO uint32_t CONCLR; /*!< (@ 0x40000018) I2C Control Clear Register*/
__IO uint32_t MMCTRL; /*!< (@ 0x4000001C) Monitor mode control register*/
__IO uint32_t ADR1; /*!< (@ 0x40000020) I2C Slave Address Register 1*/
__IO uint32_t ADR2; /*!< (@ 0x40000024) I2C Slave Address Register 2*/
__IO uint32_t ADR3; /*!< (@ 0x40000028) I2C Slave Address Register 3*/
__I uint32_t DATA_BUFFER; /*!< (@ 0x4000002C) Data buffer register */
union{
__IO uint32_t MASK[4]; /*!< (@ 0x40000030) I2C Slave address mask register */
struct{
__IO uint32_t MASK0;
__IO uint32_t MASK1;
__IO uint32_t MASK2;
__IO uint32_t MASK3;
};
};
} LPC_I2C_Type;
// ------------------------------------------------------------------------------------------------
// ----- WWDT -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x Windowed Watchdog Timer (WWDT) Modification date=3/16/2011 Major revision=0 Minor revision=3 (WWDT)
*/
typedef struct { /*!< (@ 0x40004000) WWDT Structure */
__IO uint32_t MOD; /*!< (@ 0x40004000) Watchdog mode register*/
__IO uint32_t TC; /*!< (@ 0x40004004) Watchdog timer constant register */
__IO uint32_t FEED; /*!< (@ 0x40004008) Watchdog feed sequence register */
__I uint32_t TV; /*!< (@ 0x4000400C) Watchdog timer value register */
__IO uint32_t CLKSEL; /*!< (@ 0x40004010) Watchdog clock select register. */
__IO uint32_t WARNINT; /*!< (@ 0x40004014) Watchdog Warning Interrupt compare value. */
__IO uint32_t WINDOW; /*!< (@ 0x40004018) Watchdog Window compare value. */
} LPC_WWDT_Type;
// ------------------------------------------------------------------------------------------------
// ----- USART -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x USART Modification date=3/16/2011 Major revision=0 Minor revision=3 (USART)
*/
typedef struct { /*!< (@ 0x40008000) USART Structure */
union {
__IO uint32_t DLL; /*!< (@ 0x40008000) Divisor Latch LSB. Least significant byte of the baud rate divisor value. The full divisor is used to generate a baud rate from the fractional rate divider. (DLAB=1) */
__O uint32_t THR; /*!< (@ 0x40008000) Transmit Holding Register. The next character to be transmitted is written here. (DLAB=0) */
__I uint32_t RBR; /*!< (@ 0x40008000) Receiver Buffer Register. Contains the next received character to be read. (DLAB=0) */
};
union {
__IO uint32_t IER; /*!< (@ 0x40008004) Interrupt Enable Register. Contains individual interrupt enable bits for the 7 potential USART interrupts. (DLAB=0) */
__IO uint32_t DLM; /*!< (@ 0x40008004) Divisor Latch MSB. Most significant byte of the baud rate divisor value. The full divisor is used to generate a baud rate from the fractional rate divider. (DLAB=1) */
};
union {
__O uint32_t FCR; /*!< (@ 0x40008008) FIFO Control Register. Controls USART FIFO usage and modes. */
__I uint32_t IIR; /*!< (@ 0x40008008) Interrupt ID Register. Identifies which interrupt(s) are pending. */
};
__IO uint32_t LCR; /*!< (@ 0x4000800C) Line Control Register. Contains controls for frame formatting and break generation. */
__IO uint32_t MCR; /*!< (@ 0x40008010) Modem Control Register. */
__I uint32_t LSR; /*!< (@ 0x40008014) Line Status Register. Contains flags for transmit and receive status, including line errors. */
__I uint32_t MSR; /*!< (@ 0x40008018) Modem Status Register. */
__IO uint32_t SCR; /*!< (@ 0x4000801C) Scratch Pad Register. Eight-bit temporary storage for software. */
__IO uint32_t ACR; /*!< (@ 0x40008020) Auto-baud Control Register. Contains controls for the auto-baud feature. */
__IO uint32_t ICR; /*!< (@ 0x40008024) IrDA Control Register. Enables and configures the IrDA (remote control) mode. */
__IO uint32_t FDR; /*!< (@ 0x40008028) Fractional Divider Register. Generates a clock input for the baud rate divider. */
__IO uint32_t OSR; /*!< (@ 0x4000802C) Oversampling Register. Controls the degree of oversampling during each bit time. */
__IO uint32_t TER; /*!< (@ 0x40008030) Transmit Enable Register. Turns off USART transmitter for use with software flow control. */
__I uint32_t RESERVED0[3];
__IO uint32_t HDEN; /*!< (@ 0x40008040) Half duplex enable register. */
__I uint32_t RESERVED1;
__IO uint32_t SCICTRL; /*!< (@ 0x40008048) Smart Card Interface Control register. Enables and configures the Smart Card Interface feature. */
__IO uint32_t RS485CTRL; /*!< (@ 0x4000804C) RS-485/EIA-485 Control. Contains controls to configure various aspects of RS-485/EIA-485 modes. */
__IO uint32_t RS485ADRMATCH; /*!< (@ 0x40008050) RS-485/EIA-485 address match. Contains the address match value for RS-485/EIA-485 mode. */
__IO uint32_t RS485DLY; /*!< (@ 0x40008054) RS-485/EIA-485 direction control delay. */
__IO uint32_t SYNCCTRL;
} LPC_USART_Type;
// ------------------------------------------------------------------------------------------------
// ----- Timer -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x 32-bitcounter/timers CT32B0/1 Modification date=3/16/2011 Major revision=0 Minor revision=3
*/
typedef struct { /*!< (@ 0x40014000) CT32B0 Structure */
__IO uint32_t IR; /*!< (@ 0x40014000) Interrupt Register */
__IO uint32_t TCR; /*!< (@ 0x40014004) Timer Control Register */
__IO uint32_t TC; /*!< (@ 0x40014008) Timer Counter */
__IO uint32_t PR; /*!< (@ 0x4001400C) Prescale Register */
__IO uint32_t PC; /*!< (@ 0x40014010) Prescale Counter */
__IO uint32_t MCR; /*!< (@ 0x40014014) Match Control Register */
union {
__IO uint32_t MR[4]; /*!< (@ 0x40014018) Match Register */
struct{
__IO uint32_t MR0; /*!< (@ 0x40018018) Match Register. MR0 */
__IO uint32_t MR1; /*!< (@ 0x4001801C) Match Register. MR1 */
__IO uint32_t MR2; /*!< (@ 0x40018020) Match Register. MR2 */
__IO uint32_t MR3; /*!< (@ 0x40018024) Match Register. MR3 */
};
};
__IO uint32_t CCR; /*!< (@ 0x40014028) Capture Control Register */
union{
__I uint32_t CR[4]; /*!< (@ 0x4001402C) Capture Register */
struct{
__I uint32_t CR0; /*!< (@ 0x4001802C) Capture Register. CR 0 */
__I uint32_t CR1; /*!< (@ 0x40018030) Capture Register. CR 1 */
__I uint32_t CR2; /*!< (@ 0x40018034) Capture Register. CR 2 */
__I uint32_t CR3; /*!< (@ 0x40018038) Capture Register. CR 3 */
};
};
__IO uint32_t EMR; /*!< (@ 0x4001403C) External Match Register */
__I uint32_t RESERVED0[12];
__IO uint32_t CTCR; /*!< (@ 0x40014070) Count Control Register */
__IO uint32_t PWMC; /*!< (@ 0x40014074) PWM Control Register */
} LPC_CTxxBx_Type;
// ------------------------------------------------------------------------------------------------
// ----- ADC -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x ADC Modification date=3/16/2011 Major revision=0 Minor revision=3 (ADC)
*/
typedef struct { /*!< (@ 0x4001C000) ADC Structure */
__IO uint32_t CR; /*!< (@ 0x4001C000) A/D Control Register */
__IO uint32_t GDR; /*!< (@ 0x4001C004) A/D Global Data Register */
__I uint32_t RESERVED0[1];
__IO uint32_t INTEN; /*!< (@ 0x4001C00C) A/D Interrupt Enable Register */
union{
__I uint32_t DR[8]; /*!< (@ 0x4001C010) A/D Channel Data Register*/
struct{
__IO uint32_t DR0; /*!< (@ 0x40020010) A/D Channel Data Register 0*/
__IO uint32_t DR1; /*!< (@ 0x40020014) A/D Channel Data Register 1*/
__IO uint32_t DR2; /*!< (@ 0x40020018) A/D Channel Data Register 2*/
__IO uint32_t DR3; /*!< (@ 0x4002001C) A/D Channel Data Register 3*/
__IO uint32_t DR4; /*!< (@ 0x40020020) A/D Channel Data Register 4*/
__IO uint32_t DR5; /*!< (@ 0x40020024) A/D Channel Data Register 5*/
__IO uint32_t DR6; /*!< (@ 0x40020028) A/D Channel Data Register 6*/
__IO uint32_t DR7; /*!< (@ 0x4002002C) A/D Channel Data Register 7*/
};
};
__I uint32_t STAT; /*!< (@ 0x4001C030) A/D Status Register. */
} LPC_ADC_Type;
// ------------------------------------------------------------------------------------------------
// ----- PMU -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x Power Management Unit (PMU) Modification date=3/16/2011 Major revision=0 Minor revision=3 (PMU)
*/
typedef struct { /*!< (@ 0x40038000) PMU Structure */
__IO uint32_t PCON; /*!< (@ 0x40038000) Power control register */
union{
__IO uint32_t GPREG[4]; /*!< (@ 0x40038004) General purpose register 0 */
struct{
__IO uint32_t GPREG0; /*!< (@ 0x40038004) General purpose register 0 */
__IO uint32_t GPREG1; /*!< (@ 0x40038008) General purpose register 1 */
__IO uint32_t GPREG2; /*!< (@ 0x4003800C) General purpose register 2 */
__IO uint32_t GPREG3; /*!< (@ 0x40038010) General purpose register 3 */
};
};
} LPC_PMU_Type;
// ------------------------------------------------------------------------------------------------
// ----- FLASHCTRL -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x Flash programming firmware Modification date=3/17/2011 Major revision=0 Minor revision=3 (FLASHCTRL)
*/
typedef struct { /*!< (@ 0x4003C000) FLASHCTRL Structure */
__I uint32_t RESERVED0[4];
__IO uint32_t FLASHCFG; /*!< (@ 0x4003C010) Flash memory access time configuration register */
__I uint32_t RESERVED1[3];
__IO uint32_t FMSSTART; /*!< (@ 0x4003C020) Signature start address register */
__IO uint32_t FMSSTOP; /*!< (@ 0x4003C024) Signature stop-address register */
__I uint32_t RESERVED2[1];
__I uint32_t FMSW0; /*!< (@ 0x4003C02C) Word 0 [31:0] */
__I uint32_t FMSW1; /*!< (@ 0x4003C030) Word 1 [63:32] */
__I uint32_t FMSW2; /*!< (@ 0x4003C034) Word 2 [95:64] */
__I uint32_t FMSW3; /*!< (@ 0x4003C038) Word 3 [127:96] */
__I uint32_t RESERVED3[1001];
__I uint32_t FMSTAT; /*!< (@ 0x4003CFE0) Signature generation status register */
__I uint32_t RESERVED4[1];
__IO uint32_t FMSTATCLR; /*!< (@ 0x4003CFE8) Signature generation status clear register */
} LPC_FLASHCTRL_Type;
// ------------------------------------------------------------------------------------------------
// ----- SSP0/1 -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x SSP/SPI Modification date=3/16/2011 Major revision=0 Minor revision=3 (SSP0)
*/
typedef struct { /*!< (@ 0x40040000) SSP0 Structure */
__IO uint32_t CR0; /*!< (@ 0x40040000) Control Register 0. Selects the serial clock rate, bus type, and data size. */
__IO uint32_t CR1; /*!< (@ 0x40040004) Control Register 1. Selects master/slave and other modes. */
__IO uint32_t DR; /*!< (@ 0x40040008) Data Register. Writes fill the transmit FIFO, and reads empty the receive FIFO. */
__I uint32_t SR; /*!< (@ 0x4004000C) Status Register */
__IO uint32_t CPSR; /*!< (@ 0x40040010) Clock Prescale Register */
__IO uint32_t IMSC; /*!< (@ 0x40040014) Interrupt Mask Set and Clear Register */
__I uint32_t RIS; /*!< (@ 0x40040018) Raw Interrupt Status Register */
__I uint32_t MIS; /*!< (@ 0x4004001C) Masked Interrupt Status Register */
__IO uint32_t ICR; /*!< (@ 0x40040020) SSPICR Interrupt Clear Register */
} LPC_SSPx_Type;
// ------------------------------------------------------------------------------------------------
// ----- IOCONFIG -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x I/O configuration Modification date=3/16/2011 Major revision=0 Minor revision=3 (IOCONFIG)
*/
typedef struct { /*!< (@ 0x40044000) IOCONFIG Structure */
__IO uint32_t RESET_PIO0_0; /*!< (@ 0x40044000) I/O configuration for pin RESET/PIO0_0 */
__IO uint32_t PIO0_1; /*!< (@ 0x40044004) I/O configuration for pin PIO0_1/CLKOUT/CT32B0_MAT2/USB_FTOGGLE */
__IO uint32_t PIO0_2; /*!< (@ 0x40044008) I/O configuration for pin PIO0_2/SSEL0/CT16B0_CAP0 */
__IO uint32_t PIO0_3; /*!< (@ 0x4004400C) I/O configuration for pin PIO0_3/USB_VBUS */
__IO uint32_t PIO0_4; /*!< (@ 0x40044010) I/O configuration for pin PIO0_4/SCL */
__IO uint32_t PIO0_5; /*!< (@ 0x40044014) I/O configuration for pin PIO0_5/SDA */
__IO uint32_t PIO0_6; /*!< (@ 0x40044018) I/O configuration for pin PIO0_6/USB_CONNECT/SCK0 */
__IO uint32_t PIO0_7; /*!< (@ 0x4004401C) I/O configuration for pin PIO0_7/CTS */
__IO uint32_t PIO0_8; /*!< (@ 0x40044020) I/O configuration for pin PIO0_8/MISO0/CT16B0_MAT0 */
__IO uint32_t PIO0_9; /*!< (@ 0x40044024) I/O configuration for pin PIO0_9/MOSI0/CT16B0_MAT1 */
__IO uint32_t SWCLK_PIO0_10; /*!< (@ 0x40044028) I/O configuration for pin SWCLK/PIO0_10/ SCK0/CT16B0_MAT2 */
__IO uint32_t TDI_PIO0_11; /*!< (@ 0x4004402C) I/O configuration for pin TDI/PIO0_11/AD0/CT32B0_MAT3 */
__IO uint32_t TMS_PIO0_12; /*!< (@ 0x40044030) I/O configuration for pin TMS/PIO0_12/AD1/CT32B1_CAP0 */
__IO uint32_t TDO_PIO0_13; /*!< (@ 0x40044034) I/O configuration for pin TDO/PIO0_13/AD2/CT32B1_MAT0 */
__IO uint32_t TRST_PIO0_14; /*!< (@ 0x40044038) I/O configuration for pin TRST/PIO0_14/AD3/CT32B1_MAT1 */
__IO uint32_t SWDIO_PIO0_15; /*!< (@ 0x4004403C) I/O configuration for pin SWDIO/PIO0_15/AD4/CT32B1_MAT2 */
__IO uint32_t PIO0_16; /*!< (@ 0x40044040) I/O configuration for pin PIO0_16/AD5/CT32B1_MAT3/ WAKEUP */
__IO uint32_t PIO0_17; /*!< (@ 0x40044044) I/O configuration for pin PIO0_17/RTS/CT32B0_CAP0/SCLK */
__IO uint32_t PIO0_18; /*!< (@ 0x40044048) I/O configuration for pin PIO0_18/RXD/CT32B0_MAT0 */
__IO uint32_t PIO0_19; /*!< (@ 0x4004404C) I/O configuration for pin PIO0_19/TXD/CT32B0_MAT1 */
__IO uint32_t PIO0_20; /*!< (@ 0x40044050) I/O configuration for pin PIO0_20/CT16B1_CAP0 */
__IO uint32_t PIO0_21; /*!< (@ 0x40044054) I/O configuration for pin PIO0_21/CT16B1_MAT0/MOSI1 */
__IO uint32_t PIO0_22; /*!< (@ 0x40044058) I/O configuration for pin PIO0_22/AD6/CT16B1_MAT1/MISO1 */
__IO uint32_t PIO0_23; /*!< (@ 0x4004405C) I/O configuration for pin PIO0_23/AD7 */
__IO uint32_t PIO1_0; /*!< Offset: 0x060 */
__IO uint32_t PIO1_1;
__IO uint32_t PIO1_2;
__IO uint32_t PIO1_3;
__IO uint32_t PIO1_4; /*!< Offset: 0x070 */
__IO uint32_t PIO1_5; /*!< (@ 0x40044074) I/O configuration for pin PIO1_5/CT32B1_CAP1 */
__IO uint32_t PIO1_6;
__IO uint32_t PIO1_7;
__IO uint32_t PIO1_8; /*!< Offset: 0x080 */
__IO uint32_t PIO1_9;
__IO uint32_t PIO1_10;
__IO uint32_t PIO1_11;
__IO uint32_t PIO1_12; /*!< Offset: 0x090 */
__IO uint32_t PIO1_13; /*!< (@ 0x40044094) I/O configuration for pin PIO1_13/DTR/CT16B0_MAT0/TXD */
__IO uint32_t PIO1_14; /*!< (@ 0x40044098) I/O configuration for pin PIO1_14/DSR/CT16B0_MAT1/RXD */
__IO uint32_t PIO1_15; /*!< (@ 0x4004409C) I/O configuration for pin PIO1_15/DCD/ CT16B0_MAT2/SCK1 */
__IO uint32_t PIO1_16; /*!< (@ 0x400440A0) I/O configuration for pin PIO1_16/RI/CT16B0_CAP0 */
__IO uint32_t PIO1_17;
__IO uint32_t PIO1_18;
__IO uint32_t PIO1_19; /*!< (@ 0x400440AC) I/O configuration for pin PIO1_19/DTR/SSEL1 */
__IO uint32_t PIO1_20; /*!< (@ 0x400440B0) I/O configuration for pin PIO1_20/DSR/SCK1 */
__IO uint32_t PIO1_21; /*!< (@ 0x400440B4) I/O configuration for pin PIO1_21/DCD/MISO1 */
__IO uint32_t PIO1_22; /*!< (@ 0x400440B8) I/O configuration for pin PIO1_22/RI/MOSI1 */
__IO uint32_t PIO1_23; /*!< (@ 0x400440BC) I/O configuration for pin PIO1_23/CT16B1_MAT1/SSEL1 */
__IO uint32_t PIO1_24; /*!< (@ 0x400440C0) I/O configuration for pin PIO1_24/ CT32B0_MAT0 */
__IO uint32_t PIO1_25; /*!< (@ 0x400440C4) I/O configuration for pin PIO1_25/CT32B0_MAT1 */
__IO uint32_t PIO1_26; /*!< (@ 0x400440C8) I/O configuration for pin PIO1_26/CT32B0_MAT2/ RXD */
__IO uint32_t PIO1_27; /*!< (@ 0x400440CC) I/O configuration for pin PIO1_27/CT32B0_MAT3/ TXD */
__IO uint32_t PIO1_28; /*!< (@ 0x400440D0) I/O configuration for pin PIO1_28/CT32B0_CAP0/ SCLK */
__IO uint32_t PIO1_29; /*!< (@ 0x400440D4) I/O configuration for pin PIO1_29/SCK0/ CT32B0_CAP1 */
__IO uint32_t PIO1_30;
__IO uint32_t PIO1_31; /*!< (@ 0x400440DC) I/O configuration for pin PIO1_31 */
} LPC_IOCON_Type;
// ------------------------------------------------------------------------------------------------
// ----- SYSCON -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x System control block Modification date=3/16/2011 Major revision=0 Minor revision=3 (SYSCON)
*/
typedef struct { /*!< (@ 0x40048000) SYSCON Structure */
__IO uint32_t SYSMEMREMAP; /*!< (@ 0x40048000) System memory remap */
__IO uint32_t PRESETCTRL; /*!< (@ 0x40048004) Peripheral reset control */
__IO uint32_t SYSPLLCTRL; /*!< (@ 0x40048008) System PLL control */
__I uint32_t SYSPLLSTAT; /*!< (@ 0x4004800C) System PLL status */
__IO uint32_t USBPLLCTRL; /*!< (@ 0x40048010) USB PLL control */
__I uint32_t USBPLLSTAT; /*!< (@ 0x40048014) USB PLL status */
__I uint32_t RESERVED0[2];
__IO uint32_t SYSOSCCTRL; /*!< (@ 0x40048020) System oscillator control */
__IO uint32_t WDTOSCCTRL; /*!< (@ 0x40048024) Watchdog oscillator control */
__I uint32_t RESERVED1[2];
__IO uint32_t SYSRSTSTAT; /*!< (@ 0x40048030) System reset status register */
__I uint32_t RESERVED2[3];
__IO uint32_t SYSPLLCLKSEL; /*!< (@ 0x40048040) System PLL clock source select */
__IO uint32_t SYSPLLCLKUEN; /*!< (@ 0x40048044) System PLL clock source update enable */
__IO uint32_t USBPLLCLKSEL; /*!< (@ 0x40048048) USB PLL clock source select */
__IO uint32_t USBPLLCLKUEN; /*!< (@ 0x4004804C) USB PLL clock source update enable */
__I uint32_t RESERVED3[8];
__IO uint32_t MAINCLKSEL; /*!< (@ 0x40048070) Main clock source select */
__IO uint32_t MAINCLKUEN; /*!< (@ 0x40048074) Main clock source update enable */
__IO uint32_t SYSAHBCLKDIV; /*!< (@ 0x40048078) System clock divider */
__I uint32_t RESERVED4[1];
__IO uint32_t SYSAHBCLKCTRL; /*!< (@ 0x40048080) System clock control */
__I uint32_t RESERVED5[4];
__IO uint32_t SSP0CLKDIV; /*!< (@ 0x40048094) SSP0 clock divider */
__IO uint32_t UARTCLKDIV; /*!< (@ 0x40048098) UART clock divider */
__IO uint32_t SSP1CLKDIV; /*!< (@ 0x4004809C) SSP1 clock divider */
__I uint32_t RESERVED6[8];
__IO uint32_t USBCLKSEL; /*!< (@ 0x400480C0) USB clock source select */
__IO uint32_t USBCLKUEN; /*!< (@ 0x400480C4) USB clock source update enable */
__IO uint32_t USBCLKDIV; /*!< (@ 0x400480C8) USB clock source divider */
__I uint32_t RESERVED7[5];
__IO uint32_t CLKOUTSEL; /*!< (@ 0x400480E0) CLKOUT clock source select */
__IO uint32_t CLKOUTUEN; /*!< (@ 0x400480E4) CLKOUT clock source update enable */
__IO uint32_t CLKOUTDIV; /*!< (@ 0x400480E8) CLKOUT clock divider */
__I uint32_t RESERVED8[5];
__I uint32_t PIOPORCAP0; /*!< (@ 0x40048100) POR captured PIO status 0 */
__I uint32_t PIOPORCAP1; /*!< (@ 0x40048104) POR captured PIO status 1 */
__I uint32_t RESERVED9[18];
__IO uint32_t BODCTRL; /*!< (@ 0x40048150) Brown-Out Detect */
__IO uint32_t SYSTCKCAL; /*!< (@ 0x40048154) System tick counter calibration */
__I uint32_t RESERVED10[6];
__IO uint32_t IRQLATENCY; /*!< (@ 0x40048170) IQR delay */
__IO uint32_t NMISRC; /*!< (@ 0x40048174) NMI Source Control */
__IO uint32_t PINTSEL[8]; /*!< (@ 0x40048178) GPIO Pin Interrupt Select register 0 */
__IO uint32_t USBCLKCTRL; /*!< (@ 0x40048198) USB clock control */
__I uint32_t USBCLKST; /*!< (@ 0x4004819C) USB clock status */
__I uint32_t RESERVED11[25];
__IO uint32_t STARTERP0; /*!< (@ 0x40048204) Start logic 0 interrupt wake-up enable register 0 */
__I uint32_t RESERVED12[3];
__IO uint32_t STARTERP1; /*!< (@ 0x40048214) Start logic 1 interrupt wake-up enable register 1 */
__I uint32_t RESERVED13[6];
__IO uint32_t PDSLEEPCFG; /*!< (@ 0x40048230) Power-down states in deep-sleep mode */
__IO uint32_t PDAWAKECFG; /*!< (@ 0x40048234) Power-down states for wake-up from deep-sleep */
__IO uint32_t PDRUNCFG; /*!< (@ 0x40048238) Power configuration register */
__I uint32_t RESERVED14[110];
__I uint32_t DEVICE_ID; /*!< (@ 0x400483F4) Device ID */
} LPC_SYSCON_Type;
// ------------------------------------------------------------------------------------------------
// ----- GPIO_PIN_INT -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x GPIO Modification date=3/17/2011 Major revision=0 Minor revision=3 (GPIO_PIN_INT)
*/
typedef struct { /*!< (@ 0x4004C000) GPIO_PIN_INT Structure */
__IO uint32_t ISEL; /*!< (@ 0x4004C000) Pin Interrupt Mode register */
__IO uint32_t IENR; /*!< (@ 0x4004C004) Pin Interrupt Enable (Rising) register */
__IO uint32_t SIENR; /*!< (@ 0x4004C008) Set Pin Interrupt Enable (Rising) register */
__IO uint32_t CIENR; /*!< (@ 0x4004C00C) Clear Pin Interrupt Enable (Rising) register */
__IO uint32_t IENF; /*!< (@ 0x4004C010) Pin Interrupt Enable Falling Edge / Active Level register */
__IO uint32_t SIENF; /*!< (@ 0x4004C014) Set Pin Interrupt Enable Falling Edge / Active Level register */
__IO uint32_t CIENF; /*!< (@ 0x4004C018) Clear Pin Interrupt Enable Falling Edge / Active Level address */
__IO uint32_t RISE; /*!< (@ 0x4004C01C) Pin Interrupt Rising Edge register */
__IO uint32_t FALL; /*!< (@ 0x4004C020) Pin Interrupt Falling Edge register */
__IO uint32_t IST; /*!< (@ 0x4004C024) Pin Interrupt Status register */
} LPC_GPIO_PIN_INT_Type;
// ------------------------------------------------------------------------------------------------
// ----- GPIO_GROUP_INT0/1 -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x GPIO Modification date=3/17/2011 Major revision=0 Minor revision=3 (GPIO_GROUP_INT0)
*/
typedef struct { /*!< (@ 0x4005C000) GPIO_GROUP_INT0 Structure */
__IO uint32_t CTRL; /*!< (@ 0x4005C000) GPIO grouped interrupt control register */
__I uint32_t RESERVED0[7];
__IO uint32_t PORT_POL[2]; /*!< (@ 0x4005C020) GPIO grouped interrupt port 0 polarity register */
__I uint32_t RESERVED1[6];
__IO uint32_t PORT_ENA[2]; /*!< (@ 0x4005C040) GPIO grouped interrupt port 0/1 enable register */
} LPC_GPIO_GROUP_INTx_Type;
// ------------------------------------------------------------------------------------------------
// ----- USB -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x USB2.0device controller Modification date=3/16/2011 Major revision=0 Minor revision=3 (USB)
*/
typedef struct { /*!< (@ 0x40080000) USB Structure */
__IO uint32_t DEVCMDSTAT; /*!< (@ 0x40080000) USB Device Command/Status register */
__IO uint32_t INFO; /*!< (@ 0x40080004) USB Info register */
__IO uint32_t EPLISTSTART; /*!< (@ 0x40080008) USB EP Command/Status List start address */
__IO uint32_t DATABUFSTART; /*!< (@ 0x4008000C) USB Data buffer start address */
__IO uint32_t LPM; /*!< (@ 0x40080010) Link Power Management register */
__IO uint32_t EPSKIP; /*!< (@ 0x40080014) USB Endpoint skip */
__IO uint32_t EPINUSE; /*!< (@ 0x40080018) USB Endpoint Buffer in use */
__IO uint32_t EPBUFCFG; /*!< (@ 0x4008001C) USB Endpoint Buffer Configuration register */
__IO uint32_t INTSTAT; /*!< (@ 0x40080020) USB interrupt status register */
__IO uint32_t INTEN; /*!< (@ 0x40080024) USB interrupt enable register */
__IO uint32_t INTSETSTAT; /*!< (@ 0x40080028) USB set interrupt status register */
__IO uint32_t INTROUTING; /*!< (@ 0x4008002C) USB interrupt routing register */
__I uint32_t RESERVED0[1];
__I uint32_t EPTOGGLE; /*!< (@ 0x40080034) USB Endpoint toggle register */
} LPC_USB_Type;
// ------------------------------------------------------------------------------------------------
// ----- GPIO_PORT -----
// ------------------------------------------------------------------------------------------------
/**
* @brief Product name title=UM10462 Chapter title=LPC11U1x GPIO Modification date=3/17/2011 Major revision=0 Minor revision=3 (GPIO_PORT)
*/
typedef struct {
union {
struct {
__IO uint8_t B0[32]; /*!< (@ 0x50000000) Byte pin registers port 0; pins PIO0_0 to PIO0_31 */
__IO uint8_t B1[32]; /*!< (@ 0x50000020) Byte pin registers port 1 */
};
__IO uint8_t B[64]; /*!< (@ 0x50000000) Byte pin registers port 0/1 */
};
__I uint32_t RESERVED0[1008];
union {
struct {
__IO uint32_t W0[32]; /*!< (@ 0x50001000) Word pin registers port 0 */
__IO uint32_t W1[32]; /*!< (@ 0x50001080) Word pin registers port 1 */
};
__IO uint32_t W[64]; /*!< (@ 0x50001000) Word pin registers port 0/1 */
};
uint32_t RESERVED1[960];
__IO uint32_t DIR[2]; /* 0x2000 */
uint32_t RESERVED2[30];
__IO uint32_t MASK[2]; /* 0x2080 */
uint32_t RESERVED3[30];
__IO uint32_t PIN[2]; /* 0x2100 */
uint32_t RESERVED4[30];
__IO uint32_t MPIN[2]; /* 0x2180 */
uint32_t RESERVED5[30];
__IO uint32_t SET[2]; /* 0x2200 */
uint32_t RESERVED6[30];
__O uint32_t CLR[2]; /* 0x2280 */
uint32_t RESERVED7[30];
__O uint32_t NOT[2]; /* 0x2300 */
} LPC_GPIO_Type;
#if defined ( __CC_ARM )
#pragma no_anon_unions
#endif
// ------------------------------------------------------------------------------------------------
// ----- Peripheral memory map -----
// ------------------------------------------------------------------------------------------------
#define LPC_I2C_BASE (0x40000000)
#define LPC_WWDT_BASE (0x40004000)
#define LPC_USART_BASE (0x40008000)
#define LPC_CT16B0_BASE (0x4000C000)
#define LPC_CT16B1_BASE (0x40010000)
#define LPC_CT32B0_BASE (0x40014000)
#define LPC_CT32B1_BASE (0x40018000)
#define LPC_ADC_BASE (0x4001C000)
#define LPC_PMU_BASE (0x40038000)
#define LPC_FLASHCTRL_BASE (0x4003C000)
#define LPC_SSP0_BASE (0x40040000)
#define LPC_SSP1_BASE (0x40058000)
#define LPC_IOCON_BASE (0x40044000)
#define LPC_SYSCON_BASE (0x40048000)
#define LPC_GPIO_PIN_INT_BASE (0x4004C000)
#define LPC_GPIO_GROUP_INT0_BASE (0x4005C000)
#define LPC_GPIO_GROUP_INT1_BASE (0x40060000)
#define LPC_USB_BASE (0x40080000)
#define LPC_GPIO_BASE (0x50000000)
// ------------------------------------------------------------------------------------------------
// ----- Peripheral declaration -----
// ------------------------------------------------------------------------------------------------
#define LPC_I2C ((LPC_I2C_Type *) LPC_I2C_BASE)
#define LPC_WWDT ((LPC_WWDT_Type *) LPC_WWDT_BASE)
#define LPC_USART ((LPC_USART_Type *) LPC_USART_BASE)
#define LPC_CT16B0 ((LPC_CTxxBx_Type *) LPC_CT16B0_BASE)
#define LPC_CT16B1 ((LPC_CTxxBx_Type *) LPC_CT16B1_BASE)
#define LPC_CT32B0 ((LPC_CTxxBx_Type *) LPC_CT32B0_BASE)
#define LPC_CT32B1 ((LPC_CTxxBx_Type *) LPC_CT32B1_BASE)
#define LPC_ADC ((LPC_ADC_Type *) LPC_ADC_BASE)
#define LPC_PMU ((LPC_PMU_Type *) LPC_PMU_BASE)
#define LPC_FLASHCTRL ((LPC_FLASHCTRL_Type *) LPC_FLASHCTRL_BASE)
#define LPC_SSP0 ((LPC_SSPx_Type *) LPC_SSP0_BASE)
#define LPC_SSP1 ((LPC_SSPx_Type *) LPC_SSP1_BASE)
#define LPC_IOCON ((LPC_IOCON_Type *) LPC_IOCON_BASE)
#define LPC_SYSCON ((LPC_SYSCON_Type *) LPC_SYSCON_BASE)
#define LPC_GPIO_PIN_INT ((LPC_GPIO_PIN_INT_Type *) LPC_GPIO_PIN_INT_BASE)
#define LPC_GPIO_GROUP_INT0 ((LPC_GPIO_GROUP_INTx_Type*) LPC_GPIO_GROUP_INT0_BASE)
#define LPC_GPIO_GROUP_INT1 ((LPC_GPIO_GROUP_INTx_Type*) LPC_GPIO_GROUP_INT1_BASE)
#define LPC_USB ((LPC_USB_Type *) LPC_USB_BASE)
#define LPC_GPIO ((LPC_GPIO_Type *) LPC_GPIO_BASE)
/** @} */ /* End of group Device_Peripheral_Registers */
/** @} */ /* End of group (null) */
/** @} */ /* End of group LPC11Uxx */
#ifdef __cplusplus
}
#endif
#endif // __LPC11UXX_H__

View File

@ -0,0 +1,167 @@
/*
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 LPC11Uxx/ext_lld.c
* @brief LPC11Uxx EXT subsystem low level driver source.
*
* @addtogroup EXT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_EXT || defined(__DOXYGEN__)
#include "ext_lld_isr.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief EXTD1 driver identifier.
*/
EXTDriver EXTD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level EXT driver initialization.
*
* @notapi
*/
void ext_lld_init(void) {
/* Driver initialization.*/
extObjectInit(&EXTD1);
}
/**
* @brief Configures and activates the EXT peripheral.
*
* @param[in] extp pointer to the @p EXTDriver object
*
* @notapi
*/
void ext_lld_start(EXTDriver *extp) {
int i;
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<19);
/* Configuration of automatic channels.*/
for (i = 0; i < EXT_MAX_CHANNELS; i++)
if (extp->config->channels[i].mode & EXT_CH_MODE_AUTOSTART)
ext_lld_channel_enable(extp, i);
else
ext_lld_channel_disable(extp, i);
}
/**
* @brief Deactivates the EXT peripheral.
*
* @param[in] extp pointer to the @p EXTDriver object
*
* @notapi
*/
void ext_lld_stop(EXTDriver *extp) {
int i;
if (extp->state == EXT_ACTIVE)
for (i = 0; i < EXT_MAX_CHANNELS; i++)
ext_lld_exti_irq_disable(i);
LPC_GPIO_PIN_INT->ISEL = 0;
LPC_GPIO_PIN_INT->CIENR = EXT_CHANNELS_MASK;
LPC_GPIO_PIN_INT->RISE = EXT_CHANNELS_MASK;
LPC_GPIO_PIN_INT->FALL = EXT_CHANNELS_MASK;
LPC_GPIO_PIN_INT->IST = EXT_CHANNELS_MASK;
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<19);
}
/**
* @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) {
/* program the IOpin for this channel */
LPC_SYSCON->PINTSEL[channel] = extp->config->channels[channel].iopin;
/* Programming edge irq enables */
if (extp->config->channels[channel].mode & EXT_CH_MODE_RISING_EDGE)
LPC_GPIO_PIN_INT->SIENR = (1 << channel);
else
LPC_GPIO_PIN_INT->CIENR = (1 << channel);
if (extp->config->channels[channel].mode & EXT_CH_MODE_FALLING_EDGE)
LPC_GPIO_PIN_INT->SIENF = (1 << channel);
else
LPC_GPIO_PIN_INT->CIENF = (1 << channel);
LPC_GPIO_PIN_INT->RISE = (1<<channel);
LPC_GPIO_PIN_INT->FALL = (1<<channel);
LPC_GPIO_PIN_INT->IST = (1<<channel);
ext_lld_exti_irq_enable( 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) {
(void)extp;
ext_lld_exti_irq_disable(channel);
LPC_GPIO_PIN_INT->ISEL &= ~(1 << channel);
LPC_GPIO_PIN_INT->CIENR = (1 << channel);
LPC_GPIO_PIN_INT->RISE = (1 << channel);
LPC_GPIO_PIN_INT->FALL = (1 << channel);
LPC_GPIO_PIN_INT->IST = (1 << channel);
}
#endif /* HAL_USE_EXT */
/** @} */

View File

@ -0,0 +1,152 @@
/*
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 LPC11Uxx/ext_lld.h
* @brief LPC11Uxx 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 Available number of EXT channels.
*/
#define EXT_MAX_CHANNELS 8
/**
* @brief Mask of the available channels.
*/
#define EXT_CHANNELS_MASK ((1 << EXT_MAX_CHANNELS) - 1)
/** @} */
/*===========================================================================*/
/* 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 EXT channel callback reason.
*/
typedef uint32_t expreason_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,
expreason_t reason);
/**
* @brief Channel configuration structure.
*/
typedef struct {
/**
* @brief Channel mode.
*/
uint8_t mode;
/**
* @brief IO Pin.
*/
uint8_t iopin;
/**
* @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.*/
} 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.*/
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern EXTDriver EXTD1;
#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_ */
/** @} */

View File

@ -0,0 +1,194 @@
/*
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 LPC11Uxx/ext_lld_isr.c
* @brief LPC11Uxx EXT subsystem low level driver ISR code.
*
* @addtogroup EXT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_EXT || defined(__DOXYGEN__)
#include "ext_lld_isr.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
static void ext_lld_interrupt( uint32_t n ) {
uint32_t reason;
reason = ((LPC_GPIO_PIN_INT->RISE)>> n ) & 0x01;
reason |= ((LPC_GPIO_PIN_INT->FALL)>>(n-1)) & 0x02;
LPC_GPIO_PIN_INT->RISE = (1<<n);
LPC_GPIO_PIN_INT->FALL = (1<<n);
LPC_GPIO_PIN_INT->IST = (1<<n);
EXTD1.config->channels[n].cb(&EXTD1, n, reason);
}
/**
* @brief EXT[0] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector40) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(0);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[1] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector44) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(1);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[2] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector48) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(2);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[3] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector4C) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(3);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[4] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector50) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(4);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[5] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector54) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(5);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[6] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector58) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(6);
CH_IRQ_EPILOGUE();
}
/**
* @brief EXT[7] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector5C) {
CH_IRQ_PROLOGUE();
ext_lld_interrupt(7);
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
static const uint8_t LPC11_EXT_EXTIn_IRQ_PRIORITY[] =
{ LPC11_EXT_EXTI0_IRQ_PRIORITY,
LPC11_EXT_EXTI1_IRQ_PRIORITY,
LPC11_EXT_EXTI2_IRQ_PRIORITY,
LPC11_EXT_EXTI3_IRQ_PRIORITY,
LPC11_EXT_EXTI4_IRQ_PRIORITY,
LPC11_EXT_EXTI5_IRQ_PRIORITY,
LPC11_EXT_EXTI6_IRQ_PRIORITY,
LPC11_EXT_EXTI7_IRQ_PRIORITY };
/**
* @brief Enables EXTI IRQ sources.
*
* @notapi
*/
void ext_lld_exti_irq_enable( uint32_t exti_n ) {
nvicEnableVector(FLEX_INT0_IRQn + exti_n,
CORTEX_PRIORITY_MASK(LPC11_EXT_EXTIn_IRQ_PRIORITY[exti_n]));
}
/**
* @brief Disables EXTI IRQ sources.
*
* @notapi
*/
void ext_lld_exti_irq_disable( uint32_t exti_n ) {
nvicDisableVector(FLEX_INT0_IRQn + exti_n);
}
#endif /* HAL_USE_EXT */
/** @} */

View 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 LPC11Uxx/ext_lld_isr.h
* @brief LPC11Uxx EXT subsystem low level driver ISR header.
*
* @addtogroup EXT
* @{
*/
#ifndef _EXT_LLD_ISR_H_
#define _EXT_LLD_ISR_H_
#if HAL_USE_EXT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief EXTI0 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI0_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI1 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI1_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI2 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI2_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI3 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI3_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI4 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI4_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI5 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI5_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI5_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI6 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI6_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI6_IRQ_PRIORITY 3
#endif
/**
* @brief EXTI7 interrupt priority level setting.
*/
#if !defined(LPC11_EXT_EXTI7_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC11_EXT_EXTI7_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void ext_lld_exti_irq_enable( uint32_t exti_n );
void ext_lld_exti_irq_disable( uint32_t exti_n );
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_EXT */
#endif /* _EXT_LLD_ISR_H_ */
/** @} */

View File

@ -0,0 +1,338 @@
/*
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 LPC11Uxx/gpt_lld.c
* @brief LPC11Uxx GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPT1 driver identifier.
* @note The driver GPT1 allocates the complex timer CT16B0 when enabled.
*/
#if LPC_GPT_USE_CT16B0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPT2 driver identifier.
* @note The driver GPT2 allocates the timer CT16B1 when enabled.
*/
#if LPC_GPT_USE_CT16B1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPT3 driver identifier.
* @note The driver GPT3 allocates the timer CT32B0 when enabled.
*/
#if LPC_GPT_USE_CT32B0 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPT4 driver identifier.
* @note The driver GPT4 allocates the timer CT32B1 when enabled.
*/
#if LPC_GPT_USE_CT32B1 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#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) {
gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC_GPT_USE_CT16B0
/**
* @brief CT16B0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector80) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_CT16B0 */
#if LPC_GPT_USE_CT16B1
/**
* @brief CT16B1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector84) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_CT16B0 */
#if LPC_GPT_USE_CT32B0
/**
* @brief CT32B0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector88) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_CT32B0 */
#if LPC_GPT_USE_CT32B1
/**
* @brief CT32B1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector8C) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_CT32B1 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC_GPT_USE_CT16B0
/* Driver initialization.*/
GPTD1.tmr = LPC_CT16B0;
gptObjectInit(&GPTD1);
#endif
#if LPC_GPT_USE_CT16B1
/* Driver initialization.*/
GPTD2.tmr = LPC_CT16B1;
gptObjectInit(&GPTD2);
#endif
#if LPC_GPT_USE_CT32B0
/* Driver initialization.*/
GPTD3.tmr = LPC_CT32B0;
gptObjectInit(&GPTD3);
#endif
#if LPC_GPT_USE_CT32B1
/* Driver initialization.*/
GPTD4.tmr = LPC_CT32B1;
gptObjectInit(&GPTD4);
#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 pr;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if LPC_GPT_USE_CT16B0
if (&GPTD1 == gptp) {
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7);
nvicEnableVector(TIMER_16_0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_CT16B1
if (&GPTD2 == gptp) {
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8);
nvicEnableVector(TIMER_16_1_IRQn, CORTEX_PRIORITY_MASK(3));
}
#endif
#if LPC_GPT_USE_CT32B0
if (&GPTD3 == gptp) {
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9);
nvicEnableVector(TIMER_32_0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_CT32B1
if (&GPTD4 == gptp) {
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10);
nvicEnableVector(TIMER_32_1_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
}
/* Prescaler value calculation.*/
pr = (uint16_t)((LPC_SYSCLK / gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC_SYSCLK,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tmr->PR = pr;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
#if LPC_GPT_USE_CT16B0
if (&GPTD1 == gptp) {
nvicDisableVector(TIMER_16_0_IRQn);
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 7);
}
#endif
#if LPC_GPT_USE_CT16B1
if (&GPTD2 == gptp) {
nvicDisableVector(TIMER_16_1_IRQn);
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 8);
}
#endif
#if LPC_GPT_USE_CT32B0
if (&GPTD3 == gptp) {
nvicDisableVector(TIMER_32_0_IRQn);
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 9);
}
#endif
#if LPC_GPT_USE_CT32B1
if (&GPTD4 == gptp) {
nvicDisableVector(TIMER_32_1_IRQn);
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 10);
}
#endif
}
}
/**
* @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) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @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) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 4; /* Stop TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
while (gptp->tmr->TCR & 1)
;
}
#endif /* HAL_USE_GPT */
/** @} */

Some files were not shown because too many files have changed in this diff Show More