aboutsummaryrefslogtreecommitdiff
path: root/fw
diff options
context:
space:
mode:
Diffstat (limited to 'fw')
-rw-r--r--fw/main.c122
1 files changed, 78 insertions, 44 deletions
diff --git a/fw/main.c b/fw/main.c
index 9470f5c..eb317e4 100644
--- a/fw/main.c
+++ b/fw/main.c
@@ -58,14 +58,6 @@ volatile uint8_t this_addr = 0x05; /* FIXME */
#define SR_ILED_HIGH 0x0080
#define SR_ILED_LOW 0x0040
-void shift_aux(int global_current, int leds, int active_segment) {
- spi_send(
- (global_current ? SR_ILED_HIGH : SR_ILED_LOW)
- | (leds<<1)
- | (0xff00 ^ (0x100<<active_segment)));
- strobe_aux();
-}
-
inline unsigned int stk_start() {
return SysTick->VAL;
}
@@ -74,6 +66,57 @@ inline unsigned int stk_end(unsigned int start) {
return (start - SysTick->VAL) & 0xffffff;
}
+enum {
+ SPI_AUX,
+ SPI_WORD0,
+ SPI_WORD1,
+ SPI_IDLE,
+} spi_state;
+static volatile uint32_t spi_word = 0;
+
+void cfg_spi1() {
+ /* Configure SPI controller */
+ SPI1->I2SCFGR = 0;
+ SPI1->CR2 &= ~SPI_CR2_DS_Msk;
+ SPI1->CR2 &= ~SPI_CR2_DS_Msk;
+ SPI1->CR2 |= LL_SPI_DATAWIDTH_16BIT;
+
+ /* Baud rate PCLK/2 -> 25MHz */
+ SPI1->CR1 =
+ SPI_CR1_BIDIMODE
+ | SPI_CR1_BIDIOE
+ | SPI_CR1_SSM
+ | SPI_CR1_SSI
+ | SPI_CR1_SPE
+ | (0<<SPI_CR1_BR_Pos)
+ | SPI_CR1_MSTR
+ | SPI_CR1_CPOL
+ | SPI_CR1_CPHA;
+ /* FIXME maybe try w/o BIDI */
+
+ NVIC_EnableIRQ(SPI1_IRQn);
+ NVIC_SetPriority(SPI1_IRQn, 2);
+}
+
+void SPI1_IRQHandler() {
+ switch (spi_state) {
+ case SPI_AUX:
+ strobe_aux();
+ SPI1->DR = spi_word>>16;
+ break;
+ case SPI_WORD0:
+ SPI1->DR = spi_word&0xFFFF;
+ break;
+ default:
+ tick(); /* This one is important. Otherwise, weird stuff happens and parts of the aux register seem to leak
+ into the driver registers. */
+ strobe_leds();
+ SPI1->CR2 &= ~SPI_CR2_TXEIE;
+ break;
+ }
+ spi_state ++;
+}
+
static volatile int frame_duration;
/* returns new bit time in cycles */
int shift_data() {
@@ -82,6 +125,7 @@ int shift_data() {
static int last_frame_sys_time;
/* Note: On boot, multiplexing will start with bit 1 due to the next few lines. This is perfectly ok. */
+ int rv = 1<<active_bit;
active_bit++;
if (active_bit == nbits) {
active_bit = 0;
@@ -101,25 +145,30 @@ int shift_data() {
}
}
- shift_aux(read_fb->brightness, led_state, active_segment);
+ spi_word = read_fb->data[active_bit*frame_size_words + active_segment];
+ spi_state = SPI_AUX;
+ SPI1->DR = (read_fb->brightness ? SR_ILED_HIGH : SR_ILED_LOW)
+ | (led_state<<1)
+ | (0xff00 ^ (0x100<<active_segment));
+ } else {
+ spi_word = read_fb->data[active_bit*frame_size_words + active_segment];
+ spi_state = SPI_WORD0;
+ SPI1->DR = spi_word>>16;
}
+ SPI1->CR2 |= SPI_CR2_TXEIE;
- uint32_t current_word = read_fb->data[active_bit*frame_size_words + active_segment];
- spi_send(current_word&0xffff);
- spi_send(current_word>>16);
- strobe_leds();
-
- if (current_word&0xffff)
- asm("bkpt");
-
- return 1<<active_bit;
+ return rv;
}
void cfg_timer3() {
+ /* Capture/compare channel 1 is used to generate the LED driver !OE signal. Channel 2 is used to trigger the
+ * interrupt to load the next bits in to the shift registers. Channel 2 triggers simultaneously with channel 1 at
+ * long !OE periods but will be delayed slightly to a fixed 32 timer periods (12.8us) to allow for SPI1 to finish
+ * shifting out all frame data before asserting !OE. */
TIM3->CCMR1 = 6<<TIM_CCMR1_OC1M_Pos; /* PWM Mode 1 */
- TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P; /* Inverting output */
- TIM3->DIER = TIM_DIER_CC1IE;
- TIM3->CCR1 = 1000; /* Schedule first interrupt */
+ TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2E | TIM_CCER_CC2P; /* Inverting output */
+ TIM3->DIER = TIM_DIER_CC2IE;
+ TIM3->CCR2 = 1000; /* Schedule first interrupt */
TIM3->PSC = SystemCoreClock/5000000 * 2; /* 0.40us/tick */
TIM3->ARR = 0xffff;
TIM3->EGR |= TIM_EGR_UG;
@@ -129,16 +178,18 @@ void cfg_timer3() {
NVIC_SetPriority(TIM3_IRQn, 2);
}
-
void TIM3_IRQHandler() {
//TIM3->CR1 &= ~TIM_CR1_CEN_Msk; FIXME
- /* This takes about 10us */
int period = shift_data();
TIM3->CCR1 = period;
- TIM3->CNT = 0xffff; /* To not enable OC1 right away */
+ if (period < 32) /* FIXME this constant */
+ TIM3->CCR2 = 32;
+ else
+ TIM3->CCR2 = period;
+ TIM3->CNT = 0xffff; /* To not enable OC1 riglt away */
- TIM3->SR &= ~TIM_SR_CC1IF_Msk;
+ TIM3->SR &= ~TIM_SR_CC2IF_Msk;
//TIM3->CR1 |= TIM_CR1_CEN;
}
@@ -291,29 +342,12 @@ int main(void) {
| (1<<GPIO_PUPDR_PUPDR2_Pos) /* TX */
| (1<<GPIO_PUPDR_PUPDR3_Pos); /* RX */
- /* Configure SPI controller */
- SPI1->I2SCFGR = 0;
- SPI1->CR2 &= ~SPI_CR2_DS_Msk;
- SPI1->CR2 &= ~SPI_CR2_DS_Msk;
- SPI1->CR2 |= LL_SPI_DATAWIDTH_16BIT;
-
- /* Baud rate PCLK/2 -> 25MHz */
- SPI1->CR1 =
- SPI_CR1_BIDIMODE
- | SPI_CR1_BIDIOE
- | SPI_CR1_SSM
- | SPI_CR1_SSI
- | SPI_CR1_SPE
- | (0<<SPI_CR1_BR_Pos)
- | SPI_CR1_MSTR
- | SPI_CR1_CPOL
- | SPI_CR1_CPHA;
- /* FIXME maybe try w/o BIDI */
+ cfg_spi1();
/* Clear frame buffer */
read_fb->brightness = 1;
for (int i=0; i<sizeof(read_fb->data)/sizeof(uint32_t); i++) {
- read_fb->data[i] = 0x00000000;
+ read_fb->data[i] = 0xffffffff; /* FIXME DEBUG 0x00000000; */
}
cfg_timer3();