aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2010-10-13 11:45:07 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2010-10-13 11:45:07 +0000
commit4fab7c06d1b0c9e61f6106b5b2a5c2c0b5694c34 (patch)
treee7fdadc85d78aa2143d0082d26351da49f7f2d53
parentec7455babe131ee0b8a4c228ed00a02396619a7d (diff)
downloadChibiOS-4fab7c06d1b0c9e61f6106b5b2a5c2c0b5694c34.tar.gz
ChibiOS-4fab7c06d1b0c9e61f6106b5b2a5c2c0b5694c34.tar.bz2
ChibiOS-4fab7c06d1b0c9e61f6106b5b2a5c2c0b5694c34.zip
ADC, SPI, PWM driver enhancements.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2254 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--os/hal/hal.dox23
-rw-r--r--os/hal/platforms/STM32/hal_lld_f103.h2
-rw-r--r--os/hal/platforms/STM32/pwm_lld.h67
-rw-r--r--os/hal/platforms/STM8/platform.dox2
-rw-r--r--os/hal/platforms/platforms.dox4
-rw-r--r--os/hal/src/adc.c6
-rw-r--r--os/hal/src/pwm.c10
-rw-r--r--os/hal/src/spi.c3
-rw-r--r--os/hal/templates/pwm_lld.h49
-rw-r--r--readme.txt10
-rw-r--r--testhal/STM32/PWM/main.c12
11 files changed, 160 insertions, 28 deletions
diff --git a/os/hal/hal.dox b/os/hal/hal.dox
index 4fbbccf3f..0af849111 100644
--- a/os/hal/hal.dox
+++ b/os/hal/hal.dox
@@ -337,7 +337,7 @@
active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"];
active -> complete [label="\nasync callback (full buffer)\n>acg_endcb<"];
complete -> active [label="\nadcStartConversionI()\nthen\ncallback return()"];
- complete -> ready [label="\nadcStopConversionI()\nthen\ncallback return"];
+ complete -> ready [label="\ncallback return"];
}
* @enddot
* @else
@@ -363,7 +363,7 @@
active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"];
active -> complete [label="\nasync callback (full buffer)\n>acg_endcb<"];
complete -> active [label="\nadcStartConversionI()\nthen\ncallback return()"];
- complete -> ready [label="\nadcStopConversionI()\nthen\ncallback return"];
+ complete -> ready [label="\ncallback return"];
}
* @enddot
* @endif
@@ -373,7 +373,7 @@
* the operational details follows.
*
* @subsection adc_2_1 ADC Conversion Groups
- * The ADC Conversion Group is the objects that specifies a physical
+ * 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
@@ -523,6 +523,23 @@
}
* @enddot
*
+ * @section pwm_1 PWM Operations.
+ * This driver abstracts a generic PWM times composed of:
+ * - 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
*/
diff --git a/os/hal/platforms/STM32/hal_lld_f103.h b/os/hal/platforms/STM32/hal_lld_f103.h
index b58a6778e..f1d0a0eb7 100644
--- a/os/hal/platforms/STM32/hal_lld_f103.h
+++ b/os/hal/platforms/STM32/hal_lld_f103.h
@@ -414,7 +414,7 @@
#endif
/**
- * @brief Timers 1, 8, 9, 10 and 11 clock.
+ * @brief Timers 1, 8, 9, 10, 11 clock.
*/
#if (STM32_PPRE2 == STM32_PPRE2_DIV1) || defined(__DOXYGEN__)
#define STM32_TIMCLK2 (STM32_PCLK2 * 1)
diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h
index b86ab1a8f..761c3af39 100644
--- a/os/hal/platforms/STM32/pwm_lld.h
+++ b/os/hal/platforms/STM32/pwm_lld.h
@@ -149,7 +149,6 @@ typedef void (*pwmcallback_t)(PWMDriver *pwmp);
/**
* @brief PWM driver channel configuration structure.
- * @note It could be empty on some architectures.
*/
typedef struct {
/**
@@ -225,6 +224,72 @@ struct PWMDriver {
/* Driver macros. */
/*===========================================================================*/
+/**
+ * @brief PWM clock prescaler initialization utility.
+ * @note The real clock value is rounded to the lower valid value, please
+ * make sure that the source clock frequency is a multiple of the
+ * requested PWM clock frequency.
+ * @note The calculated value must fit into an unsigned 16 bits integer.
+ *
+ * @param[in] clksrc clock source frequency, depending on the target timer
+ * cell it can be one of:
+ * - STM32_TIMCLK1
+ * - STM32_TIMCLK2
+ * .
+ * Please refer to the STM32 HAL driver documentation
+ * and/or the STM32 Reference Manual for the right clock
+ * source.
+ * @param[in] nsec PWM clock cycle time in nanoseconds
+ * @return The value to be stored in the @p pc_psc field of the
+ * @p PWMConfig structure.
+ */
+#define PWM_COMPUTE_PSC(clksrc, nsec) \
+ ((uint16_t)(((clksrc) / (1000000000 / (nsec))) - 1))
+
+/**
+ * @brief PWM cycle period initialization utility.
+ * @note The calculated value must fit into an unsigned 16 bits integer.
+ *
+ * @param[in] clkperiod PWM clock period in nanoseconds
+ * @param[in] pwmperiod PWM cycle period in nanoseconds
+ */
+#define PWM_COMPUTE_ARR(clkperiod, pwmperiod) \
+ ((uint16_t)(((clkperiod) / (1000000000 / (pwmperiod))) - 1))
+
+/**
+ * @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(pwpm, degrees) \
+ ((uint16_t)(((((uint32_t)(pwpm)->pd_config->pc_arr + 1UL) * \
+ (uint32_t)(degrees)) / 36000UL) - 1UL))
+
+/**
+ * @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(pwpm, percentage) \
+ ((uint16_t)(((((uint32_t)(pwpm)->pd_config->pc_arr + 1UL) * \
+ (uint32_t)(percentage)) / 10000UL) - 1UL))
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
diff --git a/os/hal/platforms/STM8/platform.dox b/os/hal/platforms/STM8/platform.dox
index 72694e230..20a2637af 100644
--- a/os/hal/platforms/STM8/platform.dox
+++ b/os/hal/platforms/STM8/platform.dox
@@ -19,7 +19,7 @@
/**
* @defgroup STM8_DRIVERS STM8 Drivers
- * @brief Device drivers included in the STM8 support.
+ * @brief STM8 specific support.
*
* @ingroup platforms
*/
diff --git a/os/hal/platforms/platforms.dox b/os/hal/platforms/platforms.dox
index 9596da2c7..aa25cbca4 100644
--- a/os/hal/platforms/platforms.dox
+++ b/os/hal/platforms/platforms.dox
@@ -20,10 +20,8 @@
/**
* @defgroup platforms Platforms
* @brief Supported platforms.
- * @details The implementation of the device drivers can be sligthly different
+ * @details The implementation of the device drivers can be slightly different
* on the various platforms because architectural constrains. This section
* describes the implementation of the various device drivers on the various
* supported platforms.
- *
- * @ingroup IO
*/
diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c
index c6968f11b..e18995089 100644
--- a/os/hal/src/adc.c
+++ b/os/hal/src/adc.c
@@ -176,7 +176,8 @@ void adcStartConversionI(ADCDriver *adcp,
((depth == 1) || ((depth & 1) == 0)),
"adcStartConversionI");
- chDbgAssert(adcp->ad_state == ADC_READY,
+ chDbgAssert((adcp->ad_state == ADC_READY) ||
+ (adcp->ad_state == ADC_COMPLETE),
"adcStartConversionI(), #1", "not ready");
adcp->ad_samples = samples;
adcp->ad_depth = depth;
@@ -201,8 +202,7 @@ void adcStopConversion(ADCDriver *adcp) {
chSysLock();
chDbgAssert((adcp->ad_state == ADC_READY) ||
- (adcp->ad_state == ADC_ACTIVE) ||
- (adcp->ad_state == ADC_COMPLETE),
+ (adcp->ad_state == ADC_ACTIVE),
"adcStopConversion(), #1", "invalid state");
if (adcp->ad_state != ADC_READY) {
adc_lld_stop_conversion(adcp);
diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c
index 978149ff6..13c77bfc6 100644
--- a/os/hal/src/pwm.c
+++ b/os/hal/src/pwm.c
@@ -86,8 +86,7 @@ void pwmStart(PWMDriver *pwmp, const PWMConfig *config) {
chSysLock();
chDbgAssert((pwmp->pd_state == PWM_STOP) || (pwmp->pd_state == PWM_READY),
- "pwmStart(), #1",
- "invalid state");
+ "pwmStart(), #1", "invalid state");
pwmp->pd_config = config;
pwm_lld_start(pwmp);
pwmp->pd_state = PWM_READY;
@@ -107,8 +106,7 @@ void pwmStop(PWMDriver *pwmp) {
chSysLock();
chDbgAssert((pwmp->pd_state == PWM_STOP) || (pwmp->pd_state == PWM_READY),
- "pwmStop(), #1",
- "invalid state");
+ "pwmStop(), #1", "invalid state");
pwm_lld_stop(pwmp);
pwmp->pd_state = PWM_STOP;
chSysUnlock();
@@ -133,7 +131,7 @@ void pwmEnableChannel(PWMDriver *pwmp,
chSysLock();
chDbgAssert(pwmp->pd_state == PWM_READY,
- "pwmEnableChannel(), #1", "invalid state");
+ "pwmEnableChannel(), #1", "not ready");
pwm_lld_enable_channel(pwmp, channel, width);
chSysUnlock();
}
@@ -155,7 +153,7 @@ void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) {
chSysLock();
chDbgAssert(pwmp->pd_state == PWM_READY,
- "pwmDisableChannel(), #1", "invalid state");
+ "pwmDisableChannel(), #1", "not ready");
pwm_lld_disable_channel(pwmp, channel);
chSysUnlock();
}
diff --git a/os/hal/src/spi.c b/os/hal/src/spi.c
index fe7b729bd..be5cf9452 100644
--- a/os/hal/src/spi.c
+++ b/os/hal/src/spi.c
@@ -105,6 +105,8 @@ void spiStart(SPIDriver *spip, const SPIConfig *config) {
/**
* @brief Deactivates the SPI peripheral.
+ * @note Deactivating the peripheral also enforces a release of the slave
+ * select line.
*
* @param[in] spip pointer to the @p SPIDriver object
*
@@ -117,6 +119,7 @@ void spiStop(SPIDriver *spip) {
chSysLock();
chDbgAssert((spip->spd_state == SPI_STOP) || (spip->spd_state == SPI_READY),
"spiStop(), #1", "invalid state");
+ spi_lld_unselect(spip);
spi_lld_stop(spip);
spip->spd_state = SPI_STOP;
chSysUnlock();
diff --git a/os/hal/templates/pwm_lld.h b/os/hal/templates/pwm_lld.h
index 6d499d791..07ce6eb06 100644
--- a/os/hal/templates/pwm_lld.h
+++ b/os/hal/templates/pwm_lld.h
@@ -74,6 +74,25 @@ typedef struct PWMDriver PWMDriver;
typedef void (*pwmcallback_t)(PWMDriver *pwmp);
/**
+ * @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 pcc_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 pcc_callback;
+ /* End of the mandatory fields.*/
+} PWMChannelConfig;
+
+/**
* @brief Driver configuration structure.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
@@ -116,6 +135,36 @@ struct PWMDriver {
/* Driver macros. */
/*===========================================================================*/
+/**
+ * @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(pwpm, degrees) 0
+
+/**
+ * @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(pwpm, percentage) 0
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
diff --git a/readme.txt b/readme.txt
index a0fbd9688..b03872d05 100644
--- a/readme.txt
+++ b/readme.txt
@@ -100,10 +100,12 @@
- NEW: New ADC driver model, the new model supports both synchronous and
asynchronous operations and, in general, simplifies the implementation of the
low level driver. The state diagram changed slightly changed so be careful.
-- NEW: Added pwmEnableChannelI() and pwmDisableChannelI() APIs to the PWM
- driver in order to allow channel reprogramming from within callbacks or
- interrupt handlers. The new APIs are implemented as macros so there is
- no footprint overhead.
+- NEW: Improved PWM driver model, added several macros that helps to setup
+ configuration structures and to specify pulse widths also as percentages or
+ degrees using a fixed point notation. Added new pwmEnableChannelI() and
+ pwmDisableChannelI() APIs in order to allow channel reprogramming from
+ within callbacks or interrupt handlers, the new APIs are implemented as
+ macros so there is no footprint overhead.
- NEW: Added driver fields and initialization hooks for the callback-based
drivers. The hooks are named XXX_DRIVER_EXT_FIELDS and
XXX_DRIVER_EXT_INIT_HOOK().
diff --git a/testhal/STM32/PWM/main.c b/testhal/STM32/PWM/main.c
index 287c6c43d..7f66a114e 100644
--- a/testhal/STM32/PWM/main.c
+++ b/testhal/STM32/PWM/main.c
@@ -54,8 +54,8 @@ static PWMConfig pwmcfg = {
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL}
},
- (uint16_t)(STM32_TIMCLK2 / 10000 - 1), /* 100 uS clock.*/
- (uint16_t)(10000 - 1), /* Period 1S.*/
+ PWM_COMPUTE_PSC(STM32_TIMCLK2, 100000), /* 100000 nS clock cycle. */
+ PWM_COMPUTE_ARR(100000, 1000000000), /* PWM period 1S. */
0
};
@@ -81,15 +81,15 @@ int main(int argc, char **argv) {
chThdSleepMilliseconds(2000);
/*
- * Starts the channel 0 with 50% duty cycle.
+ * Starts the channel 0 using 50% duty cycle.
*/
- pwmEnableChannel(&PWMD1, 0, 4999); /* 50% */
+ pwmEnableChannel(&PWMD1, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, 5000));
chThdSleepMilliseconds(5000);
/*
- * Changes the channel 0 with 75% duty cycle.
+ * Changes the channel 0 to 75% duty cycle.
*/
- pwmEnableChannel(&PWMD1, 0, 7499); /* 75% */
+ pwmEnableChannel(&PWMD1, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, 7500));
chThdSleepMilliseconds(5000);
/*