Update SPI driver
This commit is contained in:
		@@ -21,4 +21,42 @@
 | 
				
			|||||||
#ifndef __SPI_H__
 | 
					#ifndef __SPI_H__
 | 
				
			||||||
#define __SPI_H__
 | 
					#define __SPI_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stm32/stm32f4xx.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum stm_spi_prescaler {
 | 
				
			||||||
 | 
						SPI_PRSC_DIV2 = 0,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV4 = 1,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV8 = 2,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV16 = 3,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV32 = 4,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV64 = 5,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV128 = 6,
 | 
				
			||||||
 | 
						SPI_PRSC_DIV256 = 7,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct stm_spi_settings {
 | 
				
			||||||
 | 
						void (*cs_activate)(void);
 | 
				
			||||||
 | 
						void (*cs_deactivate)(void);
 | 
				
			||||||
 | 
						bool cpol;
 | 
				
			||||||
 | 
						bool cpha;
 | 
				
			||||||
 | 
						bool master;
 | 
				
			||||||
 | 
						bool msb_first;
 | 
				
			||||||
 | 
						enum stm_spi_prescaler prescaler;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct stm_spi_dev {
 | 
				
			||||||
 | 
						uint32_t magic;
 | 
				
			||||||
 | 
						SPI_TypeDef *spi_regs;
 | 
				
			||||||
 | 
						struct stm_spi_settings settings;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void * stm_spi_handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs, const struct stm_spi_settings *settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spi_deinit(stm_spi_handle handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int spi_transfer(stm_spi_handle handle, const uint8_t *tx, uint8_t *rx, uint32_t count, bool handle_cs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __SPI_H__ */
 | 
					#endif /* __SPI_H__ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,4 +19,146 @@
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stm-periph/spi.h>
 | 
					#include <stm-periph/spi.h>
 | 
				
			||||||
#include <stm32/stm32f4xx.h>
 | 
					#include <helper-macros/helper-macros.h>
 | 
				
			||||||
 | 
					#include <stm-periph/rcc-manager.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user