mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-02-18 17:23:52 +08:00
H7 SPI comms (#1158)
* getting health packets * start cleanup * pull state machine out * cleanup
This commit is contained in:
@@ -9,6 +9,13 @@ void tres_init(void) {
|
||||
while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0);
|
||||
|
||||
red_chiplet_init();
|
||||
|
||||
// SPI init
|
||||
set_gpio_alternate(GPIOE, 11, GPIO_AF5_SPI4);
|
||||
set_gpio_alternate(GPIOE, 12, GPIO_AF5_SPI4);
|
||||
set_gpio_alternate(GPIOE, 13, GPIO_AF5_SPI4);
|
||||
set_gpio_alternate(GPIOE, 14, GPIO_AF5_SPI4);
|
||||
register_set_bits(&(GPIOE->OSPEEDR), GPIO_OSPEEDR_OSPEED11 | GPIO_OSPEEDR_OSPEED12 | GPIO_OSPEEDR_OSPEED13 | GPIO_OSPEEDR_OSPEED14);
|
||||
}
|
||||
|
||||
const board board_tres = {
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#define SPI_BUF_SIZE 1024U
|
||||
|
||||
#ifdef STM32H7
|
||||
__attribute__((section(".ram_d1"))) uint8_t spi_buf_rx[SPI_BUF_SIZE];
|
||||
__attribute__((section(".ram_d1"))) uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
#else
|
||||
uint8_t spi_buf_rx[SPI_BUF_SIZE];
|
||||
uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
#define SPI_CHECKSUM_START 0xABU
|
||||
#define SPI_SYNC_BYTE 0x5AU
|
||||
@@ -12,21 +18,39 @@ uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
|
||||
// SPI states
|
||||
enum {
|
||||
SPI_RX_STATE_HEADER=0U,
|
||||
SPI_RX_STATE_HEADER_ACK=1U,
|
||||
SPI_RX_STATE_HEADER_NACK=2U,
|
||||
SPI_RX_STATE_DATA_RX=3U,
|
||||
SPI_RX_STATE_DATA_RX_ACK=4U,
|
||||
SPI_RX_STATE_DATA_TX=5U
|
||||
SPI_STATE_HEADER,
|
||||
SPI_STATE_HEADER_ACK,
|
||||
SPI_STATE_HEADER_NACK,
|
||||
SPI_STATE_DATA_RX,
|
||||
SPI_STATE_DATA_RX_ACK,
|
||||
SPI_STATE_DATA_TX
|
||||
};
|
||||
|
||||
uint8_t spi_state = SPI_RX_STATE_HEADER;
|
||||
uint8_t spi_state = SPI_STATE_HEADER;
|
||||
uint8_t spi_endpoint;
|
||||
uint16_t spi_data_len_mosi;
|
||||
uint16_t spi_data_len_miso;
|
||||
|
||||
#define SPI_HEADER_SIZE 7U
|
||||
|
||||
// low level SPI prototypes
|
||||
void llspi_init(void);
|
||||
void llspi_mosi_dma(uint8_t *addr, int len);
|
||||
void llspi_miso_dma(uint8_t *addr, int len);
|
||||
|
||||
void spi_init(void) {
|
||||
// clear buffers (for debugging)
|
||||
(void)memset(spi_buf_rx, 0, SPI_BUF_SIZE);
|
||||
(void)memset(spi_buf_tx, 0, SPI_BUF_SIZE);
|
||||
|
||||
// platform init
|
||||
llspi_init();
|
||||
|
||||
// Start the first packet!
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
}
|
||||
|
||||
bool check_checksum(uint8_t *data, uint16_t len) {
|
||||
// TODO: can speed this up by casting the bulk to uint32_t and xor-ing the bytes afterwards
|
||||
uint8_t checksum = SPI_CHECKSUM_START;
|
||||
@@ -35,3 +59,106 @@ bool check_checksum(uint8_t *data, uint16_t len) {
|
||||
}
|
||||
return checksum == 0U;
|
||||
}
|
||||
|
||||
void spi_handle_rx(void) {
|
||||
uint8_t next_rx_state = SPI_STATE_HEADER;
|
||||
|
||||
// parse header
|
||||
spi_endpoint = spi_buf_rx[1];
|
||||
spi_data_len_mosi = (spi_buf_rx[3] << 8) | spi_buf_rx[2];
|
||||
spi_data_len_miso = (spi_buf_rx[5] << 8) | spi_buf_rx[4];
|
||||
|
||||
if (spi_state == SPI_STATE_HEADER) {
|
||||
if ((spi_buf_rx[0] == SPI_SYNC_BYTE) && check_checksum(spi_buf_rx, SPI_HEADER_SIZE)) {
|
||||
// response: ACK and start receiving data portion
|
||||
spi_buf_tx[0] = SPI_HACK;
|
||||
next_rx_state = SPI_STATE_HEADER_ACK;
|
||||
} else {
|
||||
// response: NACK and reset state machine
|
||||
puts("- incorrect header sync or checksum "); hexdump(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
spi_buf_tx[0] = SPI_NACK;
|
||||
next_rx_state = SPI_STATE_HEADER_NACK;
|
||||
}
|
||||
llspi_miso_dma(spi_buf_tx, 1);
|
||||
} else if (spi_state == SPI_STATE_DATA_RX) {
|
||||
// We got everything! Based on the endpoint specified, call the appropriate handler
|
||||
uint16_t response_len = 0U;
|
||||
bool reponse_ack = false;
|
||||
if (check_checksum(&(spi_buf_rx[SPI_HEADER_SIZE]), spi_data_len_mosi + 1U)) {
|
||||
if (spi_endpoint == 0U) {
|
||||
if (spi_data_len_mosi >= sizeof(ControlPacket_t)) {
|
||||
ControlPacket_t ctrl;
|
||||
(void)memcpy(&ctrl, &spi_buf_rx[SPI_HEADER_SIZE], sizeof(ControlPacket_t));
|
||||
response_len = comms_control_handler(&ctrl, &spi_buf_tx[3]);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: insufficient data for control handler\n");
|
||||
}
|
||||
} else if ((spi_endpoint == 1U) || (spi_endpoint == 0x81U)) {
|
||||
if (spi_data_len_mosi == 0U) {
|
||||
response_len = comms_can_read(&(spi_buf_tx[3]), spi_data_len_miso);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: did not expect data for can_read\n");
|
||||
}
|
||||
} else if (spi_endpoint == 2U) {
|
||||
comms_endpoint2_write(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi);
|
||||
reponse_ack = true;
|
||||
} else if (spi_endpoint == 3U) {
|
||||
if (spi_data_len_mosi > 0U) {
|
||||
comms_can_write(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: did expect data for can_write\n");
|
||||
}
|
||||
} else {
|
||||
puts("SPI: unexpected endpoint"); puth(spi_endpoint); puts("\n");
|
||||
}
|
||||
} else {
|
||||
// Checksum was incorrect
|
||||
reponse_ack = false;
|
||||
puts("- incorrect data checksum\n");
|
||||
}
|
||||
|
||||
// Setup response header
|
||||
spi_buf_tx[0] = reponse_ack ? SPI_DACK : SPI_NACK;
|
||||
spi_buf_tx[1] = response_len & 0xFFU;
|
||||
spi_buf_tx[2] = (response_len >> 8) & 0xFFU;
|
||||
|
||||
// Add checksum
|
||||
uint8_t checksum = SPI_CHECKSUM_START;
|
||||
for(uint16_t i = 0U; i < (response_len + 3U); i++) {
|
||||
checksum ^= spi_buf_tx[i];
|
||||
}
|
||||
spi_buf_tx[response_len + 3U] = checksum;
|
||||
|
||||
// Write response
|
||||
llspi_miso_dma(spi_buf_tx, response_len + 4U);
|
||||
|
||||
next_rx_state = SPI_STATE_DATA_TX;
|
||||
} else {
|
||||
puts("SPI: RX unexpected state: "); puth(spi_state); puts("\n");
|
||||
}
|
||||
|
||||
spi_state = next_rx_state;
|
||||
}
|
||||
|
||||
void spi_handle_tx(void) {
|
||||
if (spi_state == SPI_STATE_HEADER_ACK) {
|
||||
// ACK was sent, queue up the RX buf for the data + checksum
|
||||
spi_state = SPI_STATE_DATA_RX;
|
||||
llspi_mosi_dma(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi + 1U);
|
||||
} else if (spi_state == SPI_STATE_HEADER_NACK) {
|
||||
// Reset state
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else if (spi_state == SPI_STATE_DATA_TX) {
|
||||
// Reset state
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else {
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
puts("SPI: TX unexpected state: "); puth(spi_state); puts("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
void spi_miso_dma(uint8_t *addr, int len) {
|
||||
void llspi_miso_dma(uint8_t *addr, int len) {
|
||||
// disable DMA
|
||||
DMA2_Stream3->CR &= ~DMA_SxCR_EN;
|
||||
register_clear_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN);
|
||||
@@ -12,7 +12,7 @@ void spi_miso_dma(uint8_t *addr, int len) {
|
||||
DMA2_Stream3->CR |= DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
void spi_mosi_dma(uint8_t *addr, int len) {
|
||||
void llspi_mosi_dma(uint8_t *addr, int len) {
|
||||
// disable DMA
|
||||
register_clear_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN);
|
||||
DMA2_Stream2->CR &= ~DMA_SxCR_EN;
|
||||
@@ -36,82 +36,8 @@ void DMA2_Stream2_IRQ_Handler(void) {
|
||||
ENTER_CRITICAL();
|
||||
DMA2->LIFCR = DMA_LIFCR_CTCIF2;
|
||||
|
||||
uint8_t next_rx_state = SPI_RX_STATE_HEADER;
|
||||
spi_handle_rx();
|
||||
|
||||
// parse header
|
||||
spi_endpoint = spi_buf_rx[1];
|
||||
spi_data_len_mosi = spi_buf_rx[3] << 8 | spi_buf_rx[2];
|
||||
spi_data_len_miso = spi_buf_rx[5] << 8 | spi_buf_rx[4];
|
||||
|
||||
if (spi_state == SPI_RX_STATE_HEADER) {
|
||||
if (spi_buf_rx[0] == SPI_SYNC_BYTE && check_checksum(spi_buf_rx, SPI_HEADER_SIZE)) {
|
||||
// response: ACK and start receiving data portion
|
||||
spi_buf_tx[0] = SPI_HACK;
|
||||
next_rx_state = SPI_RX_STATE_HEADER_ACK;
|
||||
} else {
|
||||
// response: NACK and reset state machine
|
||||
puts("SPI: incorrect header sync or checksum "); /*hexdump(spi_buf_rx, SPI_HEADER_SIZE);*/
|
||||
spi_buf_tx[0] = SPI_NACK;
|
||||
next_rx_state = SPI_RX_STATE_HEADER_NACK;
|
||||
}
|
||||
spi_miso_dma(spi_buf_tx, 1);
|
||||
} else if (spi_state == SPI_RX_STATE_DATA_RX) {
|
||||
// We got everything! Based on the endpoint specified, call the appropriate handler
|
||||
uint16_t response_len = 0U;
|
||||
bool reponse_ack = false;
|
||||
if (check_checksum(spi_buf_rx + SPI_HEADER_SIZE, spi_data_len_mosi + 1)) {
|
||||
if (spi_endpoint == 0U) {
|
||||
if (spi_data_len_mosi >= sizeof(ControlPacket_t)) {
|
||||
response_len = comms_control_handler((ControlPacket_t *)(spi_buf_rx + SPI_HEADER_SIZE), spi_buf_tx + 3);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: insufficient data for control handler\n");
|
||||
}
|
||||
} else if (spi_endpoint == 1U || spi_endpoint == 0x81U) {
|
||||
if (spi_data_len_mosi == 0U) {
|
||||
response_len = comms_can_read(spi_buf_tx + 3, spi_data_len_miso);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: did not expect data for can_read\n");
|
||||
}
|
||||
} else if (spi_endpoint == 2U) {
|
||||
comms_endpoint2_write(spi_buf_rx + SPI_HEADER_SIZE, spi_data_len_mosi);
|
||||
reponse_ack = true;
|
||||
} else if (spi_endpoint == 3U) {
|
||||
if (spi_data_len_mosi > 0U) {
|
||||
comms_can_write(spi_buf_rx + SPI_HEADER_SIZE, spi_data_len_mosi);
|
||||
reponse_ack = true;
|
||||
} else {
|
||||
puts("SPI: did expect data for can_write\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Checksum was incorrect
|
||||
reponse_ack = false;
|
||||
puts("SPI: incorrect data checksum\n");
|
||||
}
|
||||
|
||||
// Setup response header
|
||||
spi_buf_tx[0] = reponse_ack ? SPI_DACK : SPI_NACK;
|
||||
spi_buf_tx[1] = response_len & 0xFFU;
|
||||
spi_buf_tx[2] = (response_len >> 8) & 0xFFU;
|
||||
|
||||
// Add checksum
|
||||
uint8_t checksum = SPI_CHECKSUM_START;
|
||||
for(uint16_t i = 0U; i < response_len + 3; i++) {
|
||||
checksum ^= spi_buf_tx[i];
|
||||
}
|
||||
spi_buf_tx[response_len + 3] = checksum;
|
||||
|
||||
// Write response
|
||||
spi_miso_dma(spi_buf_tx, response_len + 4);
|
||||
|
||||
next_rx_state = SPI_RX_STATE_DATA_TX;
|
||||
} else {
|
||||
puts("SPI: RX unexpected state: "); puth(spi_state); puts("\n");
|
||||
}
|
||||
|
||||
spi_state = next_rx_state;
|
||||
EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
@@ -127,33 +53,15 @@ void DMA2_Stream3_IRQ_Handler(void) {
|
||||
(void)dat;
|
||||
SPI1->DR = 0U;
|
||||
|
||||
if (spi_state == SPI_RX_STATE_HEADER_ACK) {
|
||||
// ACK was sent, queue up the RX buf for the data + checksum
|
||||
spi_state = SPI_RX_STATE_DATA_RX;
|
||||
spi_mosi_dma(spi_buf_rx + SPI_HEADER_SIZE, spi_data_len_mosi + 1);
|
||||
} else if (spi_state == SPI_RX_STATE_HEADER_NACK) {
|
||||
// Reset state
|
||||
spi_state = SPI_RX_STATE_HEADER;
|
||||
spi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else if (spi_state == SPI_RX_STATE_DATA_TX) {
|
||||
// Reset state
|
||||
spi_state = SPI_RX_STATE_HEADER;
|
||||
spi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else {
|
||||
puts("SPI: TX unexpected state: "); puth(spi_state); puts("\n");
|
||||
}
|
||||
spi_handle_tx();
|
||||
}
|
||||
|
||||
// ***************************** SPI init *****************************
|
||||
void spi_init(void) {
|
||||
void llspi_init(void) {
|
||||
// We expect less than 50 transactions (including control messages and CAN buffers) at the 100Hz boardd interval. Can be raised if needed.
|
||||
REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, 5000U, FAULT_INTERRUPT_RATE_SPI_DMA)
|
||||
REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, 5000U, FAULT_INTERRUPT_RATE_SPI_DMA)
|
||||
|
||||
// Clear buffers (for debugging)
|
||||
memset(spi_buf_rx, 0, SPI_BUF_SIZE);
|
||||
memset(spi_buf_tx, 0, SPI_BUF_SIZE);
|
||||
|
||||
// Setup MOSI DMA
|
||||
register_set(&(DMA2_Stream2->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_TCIE), 0x1E077EFEU);
|
||||
register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU);
|
||||
@@ -167,10 +75,6 @@ void spi_init(void) {
|
||||
register_set(&(SPI1->CR1), SPI_CR1_SPE, 0xFFFFU);
|
||||
register_set(&(SPI1->CR2), 0U, 0xF7U);
|
||||
|
||||
// Start the first packet!
|
||||
spi_state = SPI_RX_STATE_HEADER;
|
||||
spi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
|
||||
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,91 @@
|
||||
void spi_init(void) {
|
||||
// master -> panda DMA start
|
||||
void llspi_mosi_dma(uint8_t *addr, int len) {
|
||||
// disable DMA + SPI
|
||||
register_clear_bits(&(SPI4->CFG1), SPI_CFG1_RXDMAEN);
|
||||
DMA2_Stream2->CR &= ~DMA_SxCR_EN;
|
||||
register_clear_bits(&(SPI4->CR1), SPI_CR1_SPE);
|
||||
|
||||
// drain the bus
|
||||
while ((SPI4->SR & SPI_SR_RXP) != 0U) {
|
||||
volatile uint8_t dat = SPI4->RXDR;
|
||||
(void)dat;
|
||||
}
|
||||
|
||||
// setup destination and length
|
||||
register_set(&(DMA2_Stream2->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
|
||||
DMA2_Stream2->NDTR = len;
|
||||
|
||||
// enable DMA + SPI
|
||||
DMA2_Stream2->CR |= DMA_SxCR_EN;
|
||||
register_set_bits(&(SPI4->CFG1), SPI_CFG1_RXDMAEN);
|
||||
register_set_bits(&(SPI4->CR1), SPI_CR1_SPE);
|
||||
}
|
||||
|
||||
// panda -> master DMA start
|
||||
void llspi_miso_dma(uint8_t *addr, int len) {
|
||||
// disable DMA
|
||||
DMA2_Stream3->CR &= ~DMA_SxCR_EN;
|
||||
register_clear_bits(&(SPI4->CFG1), SPI_CFG1_TXDMAEN);
|
||||
|
||||
// setup source and length
|
||||
register_set(&(DMA2_Stream3->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
|
||||
DMA2_Stream3->NDTR = len;
|
||||
|
||||
// clear under-run while we were reading
|
||||
SPI4->IFCR |= SPI_IFCR_UDRC;
|
||||
|
||||
// enable DMA
|
||||
register_set_bits(&(SPI4->CFG1), SPI_CFG1_TXDMAEN);
|
||||
DMA2_Stream3->CR |= DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
// master -> panda DMA finished
|
||||
void DMA2_Stream2_IRQ_Handler(void) {
|
||||
// Clear interrupt flag
|
||||
ENTER_CRITICAL();
|
||||
DMA2->LIFCR = DMA_LIFCR_CTCIF2;
|
||||
|
||||
spi_handle_rx();
|
||||
|
||||
EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
// panda -> master DMA finished
|
||||
void DMA2_Stream3_IRQ_Handler(void) {
|
||||
// Clear interrupt flag
|
||||
DMA2->LIFCR = DMA_LIFCR_CTCIF3;
|
||||
|
||||
// Wait until the transaction is actually finished and clear the DR
|
||||
// TODO: needs a timeout here, otherwise it gets stuck with no master clock!
|
||||
while (!(SPI4->SR & SPI_SR_TXC));
|
||||
volatile uint8_t dat = SPI4->TXDR;
|
||||
(void)dat;
|
||||
|
||||
spi_handle_tx();
|
||||
}
|
||||
|
||||
|
||||
void llspi_init(void) {
|
||||
// We expect less than 50 transactions (including control messages and CAN buffers) at the 100Hz boardd interval. Can be raised if needed.
|
||||
REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, 5000U, FAULT_INTERRUPT_RATE_SPI_DMA)
|
||||
REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, 5000U, FAULT_INTERRUPT_RATE_SPI_DMA)
|
||||
|
||||
// Setup MOSI DMA
|
||||
register_set(&(DMAMUX1_Channel10->CCR), 83U, 0xFFFFFFFFU);
|
||||
register_set(&(DMA2_Stream2->CR), (DMA_SxCR_MINC | DMA_SxCR_TCIE), 0x1E077EFEU);
|
||||
register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI4->RXDR), 0xFFFFFFFFU);
|
||||
|
||||
// Setup MISO DMA, memory -> peripheral
|
||||
register_set(&(DMAMUX1_Channel11->CCR), 84U, 0xFFFFFFFFU);
|
||||
register_set(&(DMA2_Stream3->CR), (DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE), 0x1E077EFEU);
|
||||
register_set(&(DMA2_Stream3->PAR), (uint32_t)&(SPI4->TXDR), 0xFFFFFFFFU);
|
||||
|
||||
// Enable SPI
|
||||
register_set(&(SPI4->CFG1), (7U << SPI_CFG1_DSIZE_Pos), SPI_CFG1_DSIZE_Msk);
|
||||
register_set(&(SPI4->UDRDR), 0xcd, 0xFFFFU); // set under-run value for debugging
|
||||
register_set(&(SPI4->CR1), SPI_CR1_SPE, 0xFFFFU);
|
||||
register_set(&(SPI4->CR2), 0, 0xFFFFU);
|
||||
|
||||
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ void common_init_gpio(void) {
|
||||
|
||||
void flasher_peripherals_init(void) {
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_USB1OTGHSEN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_SPI4EN;
|
||||
}
|
||||
|
||||
// Peripheral initialization
|
||||
@@ -98,6 +99,8 @@ void peripherals_init(void) {
|
||||
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOFEN;
|
||||
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOGEN;
|
||||
|
||||
RCC->APB2ENR |= RCC_APB2ENR_SPI4EN; // SPI
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // SPI DMA
|
||||
RCC->APB1LENR |= RCC_APB1LENR_TIM2EN; // main counter
|
||||
RCC->APB1LENR |= RCC_APB1LENR_TIM6EN; // interrupt timer
|
||||
RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; // clock source timer
|
||||
|
||||
Reference in New Issue
Block a user