blob: 58a1563674d398335a831c8fcc29c0b5d9625c35 [file] [log] [blame]
Brian Silverman95244d82013-12-14 12:15:46 -08001#include "cape/analog.h"
2
3#include <string.h>
4
5#include <STM32F2XX.h>
6
7#include "cape/util.h"
8
9#define SPI SPI2
10#define SPI_IRQHander SPI2_IRQHandler
11#define SPI_IRQn SPI2_IRQn
12#define RCC_APB1ENR_SPIEN RCC_APB1ENR_SPI2EN
13#define TIM TIM14
14#define TIM_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler
15#define TIM_IRQn TIM8_TRG_COM_TIM14_IRQn
16#define RCC_APB1ENR_TIMEN RCC_APB1ENR_TIM14EN
17#define CSEL_GPIO GPIOB
18#define CSEL_NUM 12
19
20#define NUM_CHANNELS 8
21
22uint16_t analog_readings[NUM_CHANNELS] __attribute__((aligned(8)));
23static volatile int current_channel;
24
25static void start_read(int channel) {
26 // This needs to wait 13 cycles between enabling the CSEL pin and starting to
27 // send data.
28 // (100ns+8ns)*120MHz = 12.96
29
30 // Clear the CSEL pin to select it.
Brian Silvermaned183e62013-12-18 15:51:16 -080031 for (int i = 0; i < 9; ++i) CSEL_GPIO->BSRRL = 1 << CSEL_NUM;
Brian Silverman95244d82013-12-14 12:15:46 -080032 current_channel = channel;
33 uint16_t data = 1 << 8 /* start bit */ |
34 0 << 7 /* not differential */ |
35 channel << 4;
36 SPI->DR = data;
37}
38
39void SPI_IRQHandler(void) {
40 uint32_t status = SPI->SR;
41 if (status & SPI_SR_RXNE) {
42 uint16_t value = SPI->DR;
43 // Masking off the high bits is important because there's nothing driving
44 // the MISO line during the time the MCU receives them.
45 analog_readings[current_channel] = value & 0x3FF;
Brian Silvermaned183e62013-12-18 15:51:16 -080046 CSEL_GPIO->BSRRH = 1 << CSEL_NUM;
Brian Silverman95244d82013-12-14 12:15:46 -080047
48 TIM->CR1 = TIM_CR1_UDIS;
49 TIM->CCR1 = 1;
50 TIM->EGR = TIM_EGR_UG;
Brian Silvermanc58872f2013-12-15 16:27:53 -080051 TIM->CR1 |= TIM_CR1_CEN;
Brian Silverman95244d82013-12-14 12:15:46 -080052 }
53}
54
55void TIM_IRQHandler(void) {
56 TIM->CR1 &= ~TIM_CR1_CEN;
57 TIM->SR = TIM_SR_CC1IF;
58
59 start_read((current_channel + 1) % NUM_CHANNELS);
60}
61
62void analog_init(void) {
63 memset(analog_readings, 0xFF, sizeof(analog_readings));
64
65 RCC->APB1ENR |= RCC_APB1ENR_SPIEN;
66 RCC->APB1ENR |= RCC_APB1ENR_TIMEN;
67
68 gpio_setup_out(CSEL_GPIO, CSEL_NUM, 3);
Brian Silvermaned183e62013-12-18 15:51:16 -080069 CSEL_GPIO->BSRRH = 1 << CSEL_NUM; // make sure it's deselected
Brian Silverman95244d82013-12-14 12:15:46 -080070
71 gpio_setup_alt(GPIOB, 13, 5); // SCK
72 gpio_setup_alt(GPIOB, 14, 5); // MISO
73 gpio_setup_alt(GPIOB, 15, 5); // MOSI
74
75 NVIC_SetPriority(SPI_IRQn, 6);
76 NVIC_EnableIRQ(SPI_IRQn);
77 NVIC_SetPriority(TIM_IRQn, 6);
78 NVIC_EnableIRQ(TIM_IRQn);
79
80 TIM->CR1 = TIM_CR1_UDIS;
81 TIM->DIER = TIM_DIER_CC1IE;
82 TIM->CCMR1 = 0;
83 // Make each tick take 500ns.
84 TIM->PSC = (30 * 500 / 1000) - 1;
85
86 SPI->CR1 = 0; // make sure it's disabled
87 SPI->CR1 =
88 SPI_CR1_DFF /* 16 bit frame */ |
89 1 << 3 /* 30MHz/4 = 7.5MHz */ |
90 SPI_CR1_MSTR /* master mode */;
91 SPI->CR2 = SPI_CR2_RXNEIE;
92 SPI->CR1 |= SPI_CR1_SPE; // enable it
93
94 start_read(0);
95}