summaryrefslogtreecommitdiff
path: root/tests/awd-timer-dma
diff options
context:
space:
mode:
authorKarl Palsson <karlp@tweak.net.au>2017-06-23 23:09:07 +0000
committerKarl Palsson <karlp@tweak.net.au>2017-09-01 21:20:39 +0000
commitb3750541774c486fdabe504434fefe1de469dba4 (patch)
tree41a66247cc12008e3d4a5c06827c99278de5790c /tests/awd-timer-dma
parent76f86f8b2c1b4b803642a30a5f94d589410fe1c2 (diff)
downloadolsndot-b3750541774c486fdabe504434fefe1de469dba4.tar.gz
olsndot-b3750541774c486fdabe504434fefe1de469dba4.tar.bz2
olsndot-b3750541774c486fdabe504434fefe1de469dba4.zip
awd-timer-dma: initial commit.
Had to figure out a few screwups before I got the AWD working properly.
Diffstat (limited to 'tests/awd-timer-dma')
-rw-r--r--tests/awd-timer-dma/Makefile.stm32l1-generic18
-rw-r--r--tests/awd-timer-dma/README.md2
-rw-r--r--tests/awd-timer-dma/awd-timer-dma.c219
-rw-r--r--tests/awd-timer-dma/awd-timer-dma.h12
-rw-r--r--tests/awd-timer-dma/main-stm32l1-generic.c42
5 files changed, 293 insertions, 0 deletions
diff --git a/tests/awd-timer-dma/Makefile.stm32l1-generic b/tests/awd-timer-dma/Makefile.stm32l1-generic
new file mode 100644
index 0000000..1ccdd67
--- /dev/null
+++ b/tests/awd-timer-dma/Makefile.stm32l1-generic
@@ -0,0 +1,18 @@
+BOARD = stm32l1-generic
+PROJECT = awd-timer-dma-$(BOARD)
+BUILD_DIR = bin-$(BOARD)
+
+SHARED_DIR = ../../shared
+
+CFILES = main-$(BOARD).c
+CFILES += awd-timer-dma.c
+CFILES += trace.c trace_stdio.c
+
+VPATH += $(SHARED_DIR)
+
+INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
+
+OPENCM3_DIR=../../libopencm3
+DEVICE=stm32l151xb
+OOCD_FILE = openocd.stm32l1-generic.cfg
+include ../../rules.mk
diff --git a/tests/awd-timer-dma/README.md b/tests/awd-timer-dma/README.md
new file mode 100644
index 0000000..58f851c
--- /dev/null
+++ b/tests/awd-timer-dma/README.md
@@ -0,0 +1,2 @@
+
+Exploring analog watchdog and timer triggered adc via dma
diff --git a/tests/awd-timer-dma/awd-timer-dma.c b/tests/awd-timer-dma/awd-timer-dma.c
new file mode 100644
index 0000000..ffb16db
--- /dev/null
+++ b/tests/awd-timer-dma/awd-timer-dma.c
@@ -0,0 +1,219 @@
+/**
+ * Testing AWD interrupt, with timer triggered dma
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/adc.h>
+#include <libopencm3/stm32/dma.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/timer.h>
+
+#include "awd-timer-dma.h"
+
+/* Everyone has tim6 right? */
+#define TIMER TIM6
+#define TIMER_RCC RCC_TIM6
+
+/* what external channel should be included? (Connect a pot here) */
+#define EXT_CHAN_RCC RCC_GPIOA
+#define EXT_CHAN_PORT GPIOA
+#define EXT_CHAN_PIN GPIO5
+#define EXT_CHAN_CHAN 5
+
+// TODO - stick this in libopencm3?
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+
+// Still have some bad shit to deal with...
+#if defined(STM32F0)
+#define SEPARATE_ADC_SAMPLING 0
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_239DOT5 // 4usec or more for tempsensor
+#define HAS_CALIBRATION 1
+#elif defined(STM32F1)
+#define SEPARATE_ADC_SAMPLING 0
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_28DOT5CYC // 17usecs or more. >~15cycles at 9Mhz
+#define SEPARATE_VREF 0
+#define HAS_CALIBRATION 1
+#define HAS_ROM_CALIBRATION 0
+#elif defined(STM32F3)
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_181DOT5CYC
+#define SAMPLE_TIME_TEMP ADC_SMPR_SMP_601DOT5CYC // 2.2usecs or more
+#define SAMPLE_TIME_VREF SAMPLE_TIME_TEMP
+#define HAS_CALIBRATION 1
+#elif defined(STM32F4)
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_28CYC
+#define SAMPLE_TIME_TEMP ADC_SMPR_SMP_144CYC // 10 usecs or more, in theory needs 840cycles!
+#define SAMPLE_TIME_VREF SAMPLE_TIME_TEMP
+#define ADC_CHANNEL_TEMP ADC_CHANNEL_TEMP_F40
+#define SEPARATE_VREF 0
+#elif defined(STM32L1)
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_48CYC
+#define SAMPLE_TIME_TEMP ADC_SMPR_SMP_192CYC
+#define SAMPLE_TIME_VREF SAMPLE_TIME_TEMP
+#define SEPARATE_VREF 0
+#elif defined(STM32L4)
+#define SAMPLE_TIME_BASIC ADC_SMPR_SMP_247DOT5CYC
+#define SAMPLE_TIME_TEMP ADC_SMPR_SMP_247DOT5CYC
+#define SAMPLE_TIME_VREF SAMPLE_TIME_TEMP
+#define HAS_CALIBRATION 1
+#else
+#error "no sample time for your target yet?!"
+#endif
+
+#ifndef SEPARATE_VREF
+#define SEPARATE_VREF 1
+#endif
+#ifndef SEPARATE_ADC_SAMPLING
+#define SEPARATE_ADC_SAMPLING 1
+#endif
+#ifndef HAS_CALIBRATION
+#define HAS_CALIBRATION 0
+#endif
+#ifndef HAS_ROM_CALIBRATION
+#define HAS_ROM_CALIBRATION 1
+#endif
+
+/* dma destination */
+static uint16_t adc_buffer[3];
+static int awd_hits;
+
+/**
+ * set up a timer from a 100khz timer base.
+ * @param sample_rate minimum is ~2hz, max is just under 100khz
+ */
+static void timer_trigger_setup(int sample_rate)
+{
+ uint32_t timer = TIMER;
+
+ timer_disable_counter(timer);
+ TIM_CNT(timer) = 0;
+ /* 100kHz base */
+ timer_set_prescaler(timer, (rcc_apb1_frequency / (100*1000)) -1);
+ timer_set_period(timer, ((100*1000)/sample_rate) - 1);
+ timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE);
+}
+
+void adc1_isr(void) {
+ if (ADC_SR(ADC1) & ADC_SR_AWD) {
+ ADC_SR(ADC1) &= ~ADC_SR_AWD;
+ awd_hits++;
+ }
+}
+
+
+void task_init(void)
+{
+ /* Some basic ADC config, that we won't touch again */
+#if defined(STM32F3)
+ /* silly f303 */
+ rcc_periph_clock_enable(RCC_ADC12);
+ rcc_adc_prescale(RCC_CFGR2_ADCxPRES_PLL_CLK_DIV_1, RCC_CFGR2_ADCxPRES_PLL_CLK_DIV_1);
+ adc_enable_regulator(ADC1);
+#elif defined (STM32L4)
+ /* same same but different */
+ rcc_periph_clock_enable(RCC_ADC1);
+ ADC_CR(ADC1) &= ~ADC_CR_DEEPPWD;
+ RCC_CCIPR |= 3 << 28; // system clock as adc clock. (with CKMODE == 0)
+ adc_enable_regulator(ADC1);
+
+ ADC_CR(ADC1) &= ~ADC_CR_ADCALDIF;
+ ADC_CR(ADC1) |= ADC_CR_ADCAL;
+ while (ADC_CR(ADC1) & ADC_CR_ADCAL);
+
+
+#else
+ rcc_periph_clock_enable(RCC_ADC1);
+ rcc_periph_clock_enable(RCC_DMA1);
+ rcc_periph_clock_enable(RCC_TIM6);
+ rcc_periph_clock_enable(EXT_CHAN_RCC);
+ gpio_mode_setup(EXT_CHAN_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, EXT_CHAN_PIN);
+ adc_power_off(ADC1);
+
+
+#endif
+#if (SEPARATE_ADC_SAMPLING == 1)
+ adc_set_sample_time_on_all_channels(ADC1, SAMPLE_TIME_BASIC);
+ adc_set_sample_time(ADC1, ADC_CHANNEL_TEMP, SAMPLE_TIME_TEMP);
+ adc_set_sample_time(ADC1, ADC_CHANNEL_VREF, SAMPLE_TIME_VREF);
+#else
+ adc_set_sample_time_on_all_channels(ADC1, SAMPLE_TIME_BASIC);
+#endif
+ adc_enable_temperature_sensor();
+#if (SEPARATE_VREF == 1)
+ adc_enable_vrefint();
+#endif
+
+ adc_enable_scan_mode(ADC1);
+ uint8_t channel_array[] = {EXT_CHAN_CHAN, ADC_CHANNEL_TEMP, ADC_CHANNEL_VREF};
+ adc_set_regular_sequence(ADC1, ARRAY_SIZE(channel_array), channel_array);
+
+ adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_TIM6_TRGO, ADC_CR2_EXTEN_RISING_EDGE);
+ /* power down when not in use please. */
+ ADC_CR1(ADC1) |= ADC_CR1_PDD | ADC_CR1_PDI;
+ adc_power_on(ADC1);
+
+#if 1
+ /* adc-v2 has this as "adc_is_power_on*/
+ while ((ADC_SR(ADC1) & ADC_SR_ADONS) == 0) {
+ ;
+ }
+#endif
+
+ /* hard code a threshold for now , around a third */
+ adc_set_watchdog_low_threshold(ADC1, 1400);
+ adc_enable_analog_watchdog_on_selected_channel(ADC1, EXT_CHAN_CHAN);
+ adc_enable_analog_watchdog_regular(ADC1);
+ adc_enable_awd_interrupt(ADC1);
+ nvic_enable_irq(NVIC_ADC1_IRQ);
+
+ dma_channel_reset(DMA1, DMA_CHANNEL1); // channel1 is adc
+ dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t)adc_buffer);
+ dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR_MSIZE_16BIT);
+ dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1);
+ dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t) & ADC_DR(ADC1));
+ dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR_PSIZE_16BIT);
+ dma_set_number_of_data(DMA1, DMA_CHANNEL1, ARRAY_SIZE(adc_buffer));
+
+// dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL1);
+ dma_enable_transfer_error_interrupt(DMA1, DMA_CHANNEL1);
+ dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1);
+
+ // This is essential to stop overflows.
+ dma_enable_circular_mode(DMA1, DMA_CHANNEL1);
+
+ dma_enable_channel(DMA1, DMA_CHANNEL1);
+ nvic_enable_irq(NVIC_DMA1_CHANNEL1_IRQ);
+
+ //Keep on requesting DMA, as long as ADC is running
+ ADC_CR2(ADC1) |= ADC_CR2_DDS;
+ adc_enable_dma(ADC1);
+
+ timer_trigger_setup(100); // slowly for now...
+ /* Reset timer count and start */
+ TIM_CNT(TIM6) = 0;
+ timer_enable_counter(TIM6);
+
+}
+
+static float adc_calc_tempf(unsigned int adc_raw_temp) {
+#if (HAS_ROM_CALIBRATION == 1)
+ float slope = ((110-30) * 1.0f)/((ST_TSENSE_CAL2_110C - ST_TSENSE_CAL1_30C) * 1.0f);
+ return slope * (adc_raw_temp - ST_TSENSE_CAL1_30C) + 30;
+#else
+ return ts_v * 1.0;
+#endif
+}
+
+void task_run(void)
+{
+ static int last_awd_hits;
+ float temperature = adc_calc_tempf(adc_buffer[1]);
+ printf("Last adc reading: %d, last temp: %f (raw=%d), last cal: %d\n",
+ adc_buffer[0], temperature, adc_buffer[1], adc_buffer[2]);
+ if (awd_hits > last_awd_hits) {
+ printf("Got %d AWD hits since last run\n", awd_hits);
+ last_awd_hits = awd_hits;
+ }
+}
diff --git a/tests/awd-timer-dma/awd-timer-dma.h b/tests/awd-timer-dma/awd-timer-dma.h
new file mode 100644
index 0000000..71bd158
--- /dev/null
+++ b/tests/awd-timer-dma/awd-timer-dma.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void task_init(void);
+ void task_run(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/awd-timer-dma/main-stm32l1-generic.c b/tests/awd-timer-dma/main-stm32l1-generic.c
new file mode 100644
index 0000000..17d6b2c
--- /dev/null
+++ b/tests/awd-timer-dma/main-stm32l1-generic.c
@@ -0,0 +1,42 @@
+/*
+ * Oct 2015 Karl Palsson <karlp@tweak.net.au>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/adc.h>
+#include <libopencm3/stm32/flash.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/usart.h>
+
+#include "trace.h"
+#include "awd-timer-dma.h"
+
+#define LED_DISCO_GREEN_PORT GPIOB
+#define LED_DISCO_GREEN_PIN GPIO7
+
+
+int main(void)
+{
+ int i;
+ int j = 0;
+ rcc_clock_setup_pll(&rcc_clock_config[RCC_CLOCK_VRANGE1_HSI_PLL_32MHZ]);
+ rcc_periph_clock_enable(RCC_GPIOB);
+ printf("hi guys!\n");
+ /* green led for ticking */
+ gpio_mode_setup(LED_DISCO_GREEN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
+ LED_DISCO_GREEN_PIN);
+
+ task_init();
+ while (1) {
+ task_run();
+ for (i = 0; i < 0x100000; i++) { /* Wait a bit. */
+ __asm__("NOP");
+ }
+ }
+
+ return 0;
+}