aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/lib/protomatter/src/arch/stm32.h
blob: 714fdc4f2f094f461582d5cef81dee97cd9217bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*!
 * @file stm32.h
 *
 * Part of Adafruit's Protomatter library for HUB75-style RGB LED matrices.
 * This file contains STM32-SPECIFIC CODE.
 *
 * Adafruit invests time and resources providing this open source code,
 * please support Adafruit and open-source hardware by purchasing
 * products from Adafruit!
 *
 * Written by Phil "Paint Your Dragon" Burgess and Jeff Epler for
 * Adafruit Industries, with contributions from the open source community.
 *
 * BSD license, all text here must be included in any redistribution.
 *
 */

#pragma once

#if defined(STM32F4_SERIES) || defined(STM32F405xx) // Arduino, CircuitPy

#if defined(ARDUINO) // COMPILING FOR ARDUINO ------------------------------

// Arduino port register lookups go here, else ones in arch.h are used.

#elif defined(CIRCUITPY) // COMPILING FOR CIRCUITPYTHON --------------------

#include "timers.h"

#undef _PM_portBitMask
#define _PM_portBitMask(pin) (1u << ((pin)&15))
#define _PM_byteOffset(pin) ((pin & 15) / 8)
#define _PM_wordOffset(pin) ((pin & 15) / 16)

#define _PM_pinOutput(pin_)                                                    \
  do {                                                                         \
    int8_t pin = (pin_);                                                       \
    GPIO_InitTypeDef GPIO_InitStruct = {0};                                    \
    GPIO_InitStruct.Pin = 1 << (pin & 15);                                     \
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;                                \
    GPIO_InitStruct.Pull = GPIO_NOPULL;                                        \
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;                         \
    HAL_GPIO_Init(pin_port(pin / 16), &GPIO_InitStruct);                       \
  } while (0)
#define _PM_pinInput(pin_)                                                     \
  do {                                                                         \
    int8_t pin = (pin_);                                                       \
    GPIO_InitTypeDef GPIO_InitStruct = {0};                                    \
    GPIO_InitStruct.Pin = 1 << (pin & 15);                                     \
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;                                    \
    GPIO_InitStruct.Pull = GPIO_NOPULL;                                        \
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;                         \
    HAL_GPIO_Init(pin_port(pin / 16), &GPIO_InitStruct);                       \
  } while (0)
#define _PM_pinHigh(pin)                                                       \
  HAL_GPIO_WritePin(pin_port(pin / 16), 1 << (pin & 15), GPIO_PIN_SET)
#define _PM_pinLow(pin)                                                        \
  HAL_GPIO_WritePin(pin_port(pin / 16), 1 << (pin & 15), GPIO_PIN_RESET)

#define _PM_PORT_TYPE uint16_t

volatile uint16_t *_PM_portOutRegister(uint32_t pin) {
  return (uint16_t *)&pin_port(pin / 16)->ODR;
}

volatile uint16_t *_PM_portSetRegister(uint32_t pin) {
  return (uint16_t *)&pin_port(pin / 16)->BSRR;
}

// To make things interesting, STM32F4xx places the set and clear
// GPIO bits within a single register.  The "clear" bits are upper, so
// offset by 1 in uint16_ts
volatile uint16_t *_PM_portClearRegister(uint32_t pin) {
  return 1 + (uint16_t *)&pin_port(pin / 16)->BSRR;
}

// TODO: was this somehow specific to TIM6?
#define _PM_timerFreq 42000000

// Because it's tied to a specific timer right now, there can be only
// one instance of the Protomatter_core struct. The Arduino library
// sets up this pointer when calling begin().
// TODO: this is no longer true, should it change?
void *_PM_protoPtr = NULL;

STATIC TIM_HandleTypeDef tim_handle;

// Timer interrupt service routine
void _PM_IRQ_HANDLER(void) {
  // Clear overflow flag:
  //_PM_TIMER_DEFAULT->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;
  _PM_row_handler(_PM_protoPtr); // In core.c
}

// Initialize, but do not start, timer
void _PM_timerInit(void *tptr) {
  TIM_TypeDef *tim_instance = (TIM_TypeDef *)tptr;
  stm_peripherals_timer_reserve(tim_instance);
  // Set IRQs at max priority and start clock
  stm_peripherals_timer_preinit(tim_instance, 0, _PM_IRQ_HANDLER);

  tim_handle.Instance = tim_instance;
  tim_handle.Init.Period = 1000; // immediately replaced.
  tim_handle.Init.Prescaler = 0;
  tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
  tim_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  HAL_TIM_Base_Init(&tim_handle);

  size_t tim_irq = stm_peripherals_timer_get_irqnum(tim_instance);
  HAL_NVIC_DisableIRQ(tim_irq);
  NVIC_ClearPendingIRQ(tim_irq);
  NVIC_SetPriority(tim_irq, 0); // Top priority
}

inline void _PM_timerStart(void *tptr, uint32_t period) {
  TIM_TypeDef *tim = tptr;
  tim->SR = 0;
  tim->ARR = period;
  tim->CR1 |= TIM_CR1_CEN;
  tim->DIER |= TIM_DIER_UIE;
  HAL_NVIC_EnableIRQ(stm_peripherals_timer_get_irqnum(tim));
}

inline uint32_t _PM_timerGetCount(void *tptr) {
  TIM_TypeDef *tim = tptr;
  return tim->CNT;
}

uint32_t _PM_timerStop(void *tptr) {
  TIM_TypeDef *tim = tptr;
  HAL_NVIC_DisableIRQ(stm_peripherals_timer_get_irqnum(tim));
  tim->CR1 &= ~TIM_CR1_CEN;
  tim->DIER &= ~TIM_DIER_UIE;
  return tim->CNT;
}
// settings from M4 for >= 150MHz, we use this part at 168MHz
#define _PM_clockHoldHigh asm("nop; nop; nop");
#define _PM_clockHoldLow asm("nop");

#define _PM_minMinPeriod 140

#endif // END CIRCUITPYTHON ------------------------------------------------

#endif // END STM32F4_SERIES || STM32F405xx