blob: 855098c724493a105f16d85c3c4df6530632ce76 [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"
Brian Silverman176c6762013-12-19 16:28:09 -08008#include "cape/led.h"
Brian Silverman95244d82013-12-14 12:15:46 -08009
10#define SPI SPI2
Brian Silverman176c6762013-12-19 16:28:09 -080011#define SPI_IRQHandler SPI2_IRQHandler
Brian Silverman95244d82013-12-14 12:15:46 -080012#define SPI_IRQn SPI2_IRQn
13#define RCC_APB1ENR_SPIEN RCC_APB1ENR_SPI2EN
14#define TIM TIM14
15#define TIM_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler
16#define TIM_IRQn TIM8_TRG_COM_TIM14_IRQn
17#define RCC_APB1ENR_TIMEN RCC_APB1ENR_TIM14EN
18#define CSEL_GPIO GPIOB
19#define CSEL_NUM 12
20
21#define NUM_CHANNELS 8
22
23uint16_t analog_readings[NUM_CHANNELS] __attribute__((aligned(8)));
24static volatile int current_channel;
Brian Silverman38188d62014-01-01 13:17:35 -080025static volatile int partial_reading;
26static volatile int frame;
Brian Silverman95244d82013-12-14 12:15:46 -080027
28static void start_read(int channel) {
29 // This needs to wait 13 cycles between enabling the CSEL pin and starting to
30 // send data.
31 // (100ns+8ns)*120MHz = 12.96
32
33 // Clear the CSEL pin to select it.
Brian Silverman391beca2013-12-28 22:32:48 -080034 for (int i = 0; i < 9; ++i) gpio_off(CSEL_GPIO, CSEL_NUM);
Brian Silverman95244d82013-12-14 12:15:46 -080035 current_channel = channel;
Brian Silverman38188d62014-01-01 13:17:35 -080036 partial_reading = 0;
37 frame = 0;
38 SPI->DR = 1; // start bit
39 uint16_t data = (1 << 15) /* not differential */ |
40 (channel << 12);
41 while (!(SPI->SR & SPI_SR_TXE));
Brian Silverman95244d82013-12-14 12:15:46 -080042 SPI->DR = data;
43}
44
45void SPI_IRQHandler(void) {
46 uint32_t status = SPI->SR;
47 if (status & SPI_SR_RXNE) {
48 uint16_t value = SPI->DR;
Brian Silverman38188d62014-01-01 13:17:35 -080049 if (frame == 0) {
50 frame = 1;
51 partial_reading = value;
52 } else {
53 // Masking off the high bits is important because there's nothing driving
54 // the MISO line during the time the MCU receives them.
55 analog_readings[current_channel] = (partial_reading << 16 | value) & 0x3FF;
56 for (int i = 0; i < 100; ++i) gpio_off(CSEL_GPIO, CSEL_NUM);
57 gpio_on(CSEL_GPIO, CSEL_NUM);
Brian Silverman95244d82013-12-14 12:15:46 -080058
Brian Silverman38188d62014-01-01 13:17:35 -080059 TIM->CR1 = TIM_CR1_OPM;
60 TIM->EGR = TIM_EGR_UG;
61 TIM->CR1 |= TIM_CR1_CEN;
62 }
Brian Silverman95244d82013-12-14 12:15:46 -080063 }
64}
65
66void TIM_IRQHandler(void) {
Brian Silverman176c6762013-12-19 16:28:09 -080067 TIM->SR = ~TIM_SR_CC1IF;
Brian Silverman95244d82013-12-14 12:15:46 -080068
69 start_read((current_channel + 1) % NUM_CHANNELS);
70}
71
72void analog_init(void) {
73 memset(analog_readings, 0xFF, sizeof(analog_readings));
74
75 RCC->APB1ENR |= RCC_APB1ENR_SPIEN;
76 RCC->APB1ENR |= RCC_APB1ENR_TIMEN;
77
78 gpio_setup_out(CSEL_GPIO, CSEL_NUM, 3);
Brian Silverman391beca2013-12-28 22:32:48 -080079 gpio_on(CSEL_GPIO, CSEL_NUM); // deselect it
Brian Silverman95244d82013-12-14 12:15:46 -080080
81 gpio_setup_alt(GPIOB, 13, 5); // SCK
82 gpio_setup_alt(GPIOB, 14, 5); // MISO
83 gpio_setup_alt(GPIOB, 15, 5); // MOSI
84
85 NVIC_SetPriority(SPI_IRQn, 6);
86 NVIC_EnableIRQ(SPI_IRQn);
87 NVIC_SetPriority(TIM_IRQn, 6);
88 NVIC_EnableIRQ(TIM_IRQn);
89
Brian Silvermanffeef3f2013-12-22 14:06:23 -080090 TIM->CR1 = TIM_CR1_OPM;
Brian Silverman95244d82013-12-14 12:15:46 -080091 TIM->DIER = TIM_DIER_CC1IE;
92 TIM->CCMR1 = 0;
Brian Silverman38188d62014-01-01 13:17:35 -080093 // Make each tick take 1500ns.
94 TIM->PSC = (60 * 1500 / 1000) - 1;
Brian Silverman176c6762013-12-19 16:28:09 -080095 // Call the interrupt after 1 tick.
96 TIM->CCR1 = 1;
Brian Silverman95244d82013-12-14 12:15:46 -080097
98 SPI->CR1 = 0; // make sure it's disabled
99 SPI->CR1 =
100 SPI_CR1_DFF /* 16 bit frame */ |
Brian Silverman176c6762013-12-19 16:28:09 -0800101 SPI_CR1_SSM | SPI_CR1_SSI | /* don't watch for other masters */
Brian Silverman38188d62014-01-01 13:17:35 -0800102 3 << 3 /* 30MHz/16 = 1.875MHz */ |
Brian Silverman95244d82013-12-14 12:15:46 -0800103 SPI_CR1_MSTR /* master mode */;
104 SPI->CR2 = SPI_CR2_RXNEIE;
105 SPI->CR1 |= SPI_CR1_SPE; // enable it
106
107 start_read(0);
108}