/* Reflow Oven Controller * * Copyright (C) 2021 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ #include #include #include #include #define STM_SPI_DEV_MAGIC 0x5A678F5CUL struct spi_rcc_lookup_pair { SPI_TypeDef *spi_regs; volatile uint32_t *rcc_reg; uint32_t bit_no; }; const struct spi_rcc_lookup_pair rcc_lookup[3] = { {SPI1, &RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_SPI1EN)}, {SPI2, &RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_SPI2EN)}, {SPI3, &RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_SPI3EN)}, }; static const struct spi_rcc_lookup_pair *spi_find_rcc_reg_and_bit(SPI_TypeDef *spi_regs) { uint32_t i; const struct spi_rcc_lookup_pair *ret = NULL; for (i = 0; i < COUNT_OF(rcc_lookup); i++) { if (rcc_lookup[i].spi_regs == spi_regs) { ret = &rcc_lookup[i]; break; } } return ret; } static struct stm_spi_dev *spi_handle_to_struct(stm_spi_handle handle) { struct stm_spi_dev *dev; dev = (struct stm_spi_dev *)handle; if (dev == NULL) return NULL; if (dev->magic != STM_SPI_DEV_MAGIC) return NULL; return dev; } stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs, const struct stm_spi_settings *settings) { stm_spi_handle ret_handle = NULL; uint32_t reg_val; const struct spi_rcc_lookup_pair *rcc_pair; if (!spi_dev_struct || !spi_regs || !settings) goto exit; if (!settings->cs_activate || !settings->cs_deactivate) goto exit; rcc_pair = spi_find_rcc_reg_and_bit(spi_regs); if (!rcc_pair) goto exit; memcpy(&spi_dev_struct->settings, settings, sizeof(struct stm_spi_settings)); spi_dev_struct->spi_regs = spi_regs; rcc_manager_enable_clock(rcc_pair->rcc_reg, rcc_pair->bit_no); reg_val = 0; if (settings->cpha) reg_val |= SPI_CR1_CPHA; if (settings->cpol) reg_val |= SPI_CR1_CPOL; if (settings->master) reg_val |= SPI_CR1_MSTR; reg_val |= (settings->prescaler & 0x7) << 3; reg_val |= SPI_CR1_SPE | SPI_CR1_SSI | SPI_CR1_SSM; if (!settings->msb_first) reg_val |= SPI_CR1_LSBFIRST; spi_regs->CR2 = 0UL; spi_regs->CR1 = reg_val; ret_handle = spi_dev_struct; spi_dev_struct->settings.cs_deactivate(); exit: return ret_handle; } void spi_deinit(stm_spi_handle handle) { const struct spi_rcc_lookup_pair *rcc_pair; struct stm_spi_dev *dev; dev = spi_handle_to_struct(handle); if (!dev) return; dev->spi_regs->CR1 = 0; dev->spi_regs->CR2 = 0; rcc_pair = spi_find_rcc_reg_and_bit(dev->spi_regs); if (!rcc_pair) rcc_manager_disable_clock(rcc_pair->rcc_reg, rcc_pair->bit_no); } static uint8_t transfer_byte(uint8_t byte, struct stm_spi_dev *dev) { while (dev->spi_regs->SR & SPI_SR_BSY); dev->spi_regs->DR = (uint16_t)byte; __DSB(); while((dev->spi_regs->SR & SPI_SR_BSY) || !(dev->spi_regs->SR & SPI_SR_TXE)); return (uint8_t)dev->spi_regs->DR; } int spi_transfer(stm_spi_handle handle, const uint8_t *tx, uint8_t *rx, uint32_t count, bool handle_cs) { struct stm_spi_dev *dev; uint8_t tx_byte; uint8_t rx_byte; uint32_t idx; dev = spi_handle_to_struct(handle); if (!dev) return -1001; if (handle_cs) dev->settings.cs_activate(); for (idx = 0; idx < count; idx++) { tx_byte = (tx ? tx[idx] : 0U); rx_byte = transfer_byte(tx_byte, dev); if (rx) rx[idx] = rx_byte; } if (handle_cs) dev->settings.cs_deactivate(); return 0; }