aboutsummaryrefslogtreecommitdiffstats
path: root/demos/ARMCM3-STM32L152-DISCOVERY/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'demos/ARMCM3-STM32L152-DISCOVERY/main.c')
-rw-r--r--demos/ARMCM3-STM32L152-DISCOVERY/main.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/demos/ARMCM3-STM32L152-DISCOVERY/main.c b/demos/ARMCM3-STM32L152-DISCOVERY/main.c
new file mode 100644
index 000000000..12e810a22
--- /dev/null
+++ b/demos/ARMCM3-STM32L152-DISCOVERY/main.c
@@ -0,0 +1,246 @@
+/*
+ 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.
+*/
+
+#include "ch.h"
+#include "hal.h"
+#include "test.h"
+
+static void pwmpcb(PWMDriver *pwmp);
+static void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n);
+static void spicb(SPIDriver *spip);
+
+/* Total number of channels to be sampled by a single ADC operation.*/
+#define ADC_GRP1_NUM_CHANNELS 2
+
+/* Depth of the conversion buffer, channels are sampled four times each.*/
+#define ADC_GRP1_BUF_DEPTH 4
+
+/*
+ * ADC samples buffer.
+ */
+static adcsample_t samples[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
+
+/*
+ * ADC conversion group.
+ * Mode: Linear buffer, 4 samples of 2 channels, SW triggered.
+ * Channels: IN10 (48 cycles sample time)
+ * Sensor (192 cycles sample time)
+ */
+static const ADCConversionGroup adcgrpcfg = {
+ FALSE,
+ ADC_GRP1_NUM_CHANNELS,
+ adccb,
+ NULL,
+ /* HW dependent part.*/
+ 0, /* CR1 */
+ ADC_CR2_SWSTART, /* CR2 */
+ 0,
+ ADC_SMPR2_SMP_AN10(ADC_SAMPLE_48) | ADC_SMPR2_SMP_SENSOR(ADC_SAMPLE_192),
+ 0,
+ ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
+ 0,
+ 0,
+ 0,
+ ADC_SQR5_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR5_SQ1_N(ADC_CHANNEL_SENSOR)
+};
+
+/*
+ * PWM configuration structure.
+ * Cyclic callback enabled, channels 1 and 2 enabled without callbacks,
+ * the active state is a logic one.
+ */
+static PWMConfig pwmcfg = {
+ 10000, /* 10kHz PWM clock frequency. */
+ 10000, /* PWM period 1S (in ticks). */
+ pwmpcb,
+ {
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL},
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL},
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL}
+ },
+ /* HW dependent part.*/
+ 0
+};
+
+/*
+ * SPI configuration structure.
+ * Maximum speed (12MHz), CPHA=0, CPOL=0, 16bits frames, MSb transmitted first.
+ * The slave select line is the pin GPIOA_SPI1NSS on the port GPIOA.
+ */
+static const SPIConfig spicfg = {
+ spicb,
+ /* HW dependent part.*/
+ GPIOB,
+ 12,
+ SPI_CR1_DFF
+};
+
+/*
+ * PWM cyclic callback.
+ * A new ADC conversion is started.
+ */
+static void pwmpcb(PWMDriver *pwmp) {
+
+ (void)pwmp;
+
+ /* Starts an asynchronous ADC conversion operation, the conversion
+ will be executed in parallel to the current PWM cycle and will
+ terminate before the next PWM cycle.*/
+ chSysLockFromIsr();
+ adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP1_BUF_DEPTH);
+ chSysUnlockFromIsr();
+}
+
+/*
+ * ADC end conversion callback.
+ * The PWM channels are reprogrammed using the latest ADC samples.
+ * The latest samples are transmitted into a single SPI transaction.
+ */
+void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
+
+ (void) buffer; (void) n;
+ /* Note, only in the ADC_COMPLETE state because the ADC driver fires an
+ intermediate callback when the buffer is half full.*/
+ if (adcp->state == ADC_COMPLETE) {
+ adcsample_t avg_ch1, avg_ch2;
+
+ /* Calculates the average values from the ADC samples.*/
+ avg_ch1 = (samples[0] + samples[2] + samples[4] + samples[6]) / 4;
+ avg_ch2 = (samples[1] + samples[3] + samples[5] + samples[7]) / 4;
+
+ chSysLockFromIsr();
+
+ /* Changes the channels pulse width, the change will be effective
+ starting from the next cycle.*/
+ pwmEnableChannelI(&PWMD4, 0, PWM_FRACTION_TO_WIDTH(&PWMD4, 4096, avg_ch1));
+ pwmEnableChannelI(&PWMD4, 1, PWM_FRACTION_TO_WIDTH(&PWMD4, 4096, avg_ch2));
+
+ /* SPI slave selection and transmission start.*/
+ spiSelectI(&SPID2);
+ spiStartSendI(&SPID2, ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH, samples);
+
+ chSysUnlockFromIsr();
+ }
+}
+
+/*
+ * SPI end transfer callback.
+ */
+static void spicb(SPIDriver *spip) {
+
+ /* On transfer end just releases the slave select line.*/
+ chSysLockFromIsr();
+ spiUnselectI(spip);
+ chSysUnlockFromIsr();
+}
+
+/*
+ * This is a periodic thread that does absolutely nothing except increasing
+ * a seconds counter.
+ */
+static WORKING_AREA(waThread1, 128);
+static msg_t Thread1(void *arg) {
+ static uint32_t seconds_counter;
+
+ (void)arg;
+ chRegSetThreadName("counter");
+ while (TRUE) {
+ chThdSleepMilliseconds(1000);
+ seconds_counter++;
+ }
+}
+
+/*
+ * Application entry point.
+ */
+int main(void) {
+
+ /*
+ * System initializations.
+ * - HAL initialization, this also initializes the configured device drivers
+ * and performs the board-specific initializations.
+ * - Kernel initialization, the main() function becomes a thread and the
+ * RTOS is active.
+ */
+ halInit();
+ chSysInit();
+
+ /*
+ * Activates the serial driver 1 using the driver default configuration.
+ * PA9 and PA10 are routed to USART1.
+ */
+ sdStart(&SD1, NULL);
+ palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(7));
+ palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(7));
+
+ /*
+ * If the user button is pressed after the reset then the test suite is
+ * executed immediately before activating the various device drivers in
+ * order to not alter the benchmark scores.
+ */
+ if (palReadPad(GPIOA, GPIOA_BUTTON))
+ TestThread(&SD1);
+
+ /*
+ * Initializes the SPI driver 2. The SPI2 signals are routed as follow:
+ * PB12 - NSS.
+ * PB13 - SCK.
+ * PB14 - MISO.
+ * PB15 - MOSI.
+ */
+ spiStart(&SPID2, &spicfg);
+ palSetPad(GPIOB, 12);
+ palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |
+ PAL_STM32_OSPEED_HIGHEST); /* NSS. */
+ palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |
+ PAL_STM32_OSPEED_HIGHEST); /* SCK. */
+ palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5)); /* MISO. */
+ palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |
+ PAL_STM32_OSPEED_HIGHEST); /* MOSI. */
+
+ /*
+ * Initializes the ADC driver 1 and enable the thermal sensor.
+ * The pin PC0 on the port GPIOC is programmed as analog input.
+ */
+ adcStart(&ADCD1, NULL);
+ adcSTM32EnableTSVREFE();
+ palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG);
+
+ /*
+ * Initializes the PWM driver 4, routes the TIM4 outputs to the board LEDs.
+ */
+ pwmStart(&PWMD4, &pwmcfg);
+ palSetPadMode(GPIOB, GPIOB_LED4, PAL_MODE_ALTERNATE(2));
+ palSetPadMode(GPIOB, GPIOB_LED3, PAL_MODE_ALTERNATE(2));
+
+ /*
+ * Creates the example thread.
+ */
+ chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
+
+ /*
+ * Normal main() thread activity, in this demo it does nothing except
+ * sleeping in a loop and check the button state, when the button is
+ * pressed the test procedure is launched with output on the serial
+ * driver 1.
+ */
+ while (TRUE) {
+ if (palReadPad(GPIOA, GPIOA_BUTTON))
+ TestThread(&SD1);
+ chThdSleepMilliseconds(500);
+ }
+}