diff options
| author | Keith Packard <keithp@keithp.com> | 2016-04-02 19:42:44 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2016-04-02 19:45:06 -0700 | 
| commit | 9f9d77b6d025d8285e362e53a8f728ec47adb234 (patch) | |
| tree | aa69b19c626369babeabb974a5eceb676c056487 | |
| parent | f5e6caab78f4ca0e5c8a2d96ef53b8752d64f4b3 (diff) | |
altos/stmf0: Add SPI driver.
This also changes the DMA interface a bit so we can select for
interrupts on only the interesting channels.
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | src/stmf0/ao_adc_fast.c | 4 | ||||
| -rw-r--r-- | src/stmf0/ao_dma_stm.c | 34 | ||||
| -rw-r--r-- | src/stmf0/ao_spi_stm.c | 478 | ||||
| -rw-r--r-- | src/stmf0/stm32f0.h | 34 | 
4 files changed, 535 insertions, 15 deletions
diff --git a/src/stmf0/ao_adc_fast.c b/src/stmf0/ao_adc_fast.c index f6740b0e..0a2e2c5c 100644 --- a/src/stmf0/ao_adc_fast.c +++ b/src/stmf0/ao_adc_fast.c @@ -72,7 +72,9 @@ _ao_adc_start(void)  			    (1 << STM_DMA_CCR_MINC) |  			    (0 << STM_DMA_CCR_PINC) |  			    (0 << STM_DMA_CCR_CIRC) | -			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); +  	ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_dma_done);  	ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); diff --git a/src/stmf0/ao_dma_stm.c b/src/stmf0/ao_dma_stm.c index 78fabe18..e90c6bf8 100644 --- a/src/stmf0/ao_dma_stm.c +++ b/src/stmf0/ao_dma_stm.c @@ -28,9 +28,7 @@ static uint8_t ao_dma_allocated[STM_NUM_DMA];  static uint8_t ao_dma_mutex[STM_NUM_DMA];  static uint8_t ao_dma_active; -#define id(ch)		STM_DMA_INDEX(ch) -#define id_mask(id)	(STM_DMA_ISR_MASK << (id)) -#define ch_mask(ch)	id_mask(id(ch)) +#define ch_mask(id)	(STM_DMA_ISR_MASK << STM_DMA_ISR(id))  static void  ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) { @@ -41,7 +39,7 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {  	/* Ack them */  	stm_dma.ifcr = isr;  	for (index = low_index; index <= high_index; index++) { -		if (isr & id_mask(index)) { +		if (isr & ch_mask(index)) {  			if (ao_dma_config[index].isr)  				(*ao_dma_config[index].isr)(index);  			else { @@ -52,9 +50,25 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {  	}  } -void stm_dma_ch1_isr(void) { ao_dma_isr(id(1), id(1), ch_mask(1)); } -void stm_dma_ch2_3_isr(void) { ao_dma_isr(id(2), id(3), ch_mask(2) | ch_mask(3)); } -void stm_dma1_ch4_5_6_isr(void) { ao_dma_isr(id(4), id(6), ch_mask(4) | ch_mask(5) | ch_mask(6)); } +void stm_dma_ch1_isr(void) { +	ao_dma_isr(STM_DMA_INDEX(1), +		   STM_DMA_INDEX(1), +		   ch_mask(STM_DMA_INDEX(1))); +} + +void stm_dma_ch2_3_isr(void) { +	ao_dma_isr(STM_DMA_INDEX(2), +		   STM_DMA_INDEX(3), +		   ch_mask(STM_DMA_INDEX(2)) | +		   ch_mask(STM_DMA_INDEX(3))); +} + +void stm_dma1_ch4_5_6_isr(void) { +	ao_dma_isr(STM_DMA_INDEX(4), STM_DMA_INDEX(6), +		   ch_mask(STM_DMA_INDEX(4)) | +		   ch_mask(STM_DMA_INDEX(5)) | +		   ch_mask(STM_DMA_INDEX(6))); +}  void  ao_dma_set_transfer(uint8_t 		index, @@ -73,11 +87,12 @@ ao_dma_set_transfer(uint8_t 		index,  		if (ao_dma_active++ == 0)  			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMAEN);  		); -	stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE); +	ao_dma_config[index].isr = NULL; +	ao_dma_done[index] = 0;  	stm_dma.channel[index].cndtr = count;  	stm_dma.channel[index].cpar = peripheral;  	stm_dma.channel[index].cmar = memory; -	ao_dma_config[index].isr = NULL; +	stm_dma.channel[index].ccr = ccr;  }  void @@ -89,7 +104,6 @@ ao_dma_set_isr(uint8_t index, void (*isr)(int))  void  ao_dma_start(uint8_t index)  { -	ao_dma_done[index] = 0;  	stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN);  } diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c new file mode 100644 index 00000000..55bf59d2 --- /dev/null +++ b/src/stmf0/ao_spi_stm.c @@ -0,0 +1,478 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> + +struct ao_spi_stm_info { +	uint8_t	miso_dma_index; +	uint8_t mosi_dma_index; +	struct stm_spi *stm_spi; +}; + +static uint8_t		ao_spi_mutex[STM_NUM_SPI]; +static uint8_t		ao_spi_index[STM_NUM_SPI]; + +static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = { +	{ +		.miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX), +		.mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX), +		&stm_spi1 +	}, +	{ +		.miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX), +		.mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX), +		&stm_spi2 +	} +}; + +static uint8_t	spi_dev_null; + + + +#define SPI_CR2	((0 << STM_SPI_CR2_LDMA_TX) |				\ +		 (0 << STM_SPI_CR2_LDMA_RX) |				\ +		 (1 << STM_SPI_CR2_FRXTH) |				\ +		 (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) |			\ +		 (0 << STM_SPI_CR2_TXEIE) |				\ +		 (0 << STM_SPI_CR2_RXNEIE) |				\ +		 (0 << STM_SPI_CR2_ERRIE) |				\ +		 (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) |	\ +		 (0 << STM_SPI_CR2_NSSP) |				\ +		 (0 << STM_SPI_CR2_SSOE)) + +#define SPI_CR2_DMA	(SPI_CR2 |			\ +			 (1 << STM_SPI_CR2_TXDMAEN) |	\ +			 (1 << STM_SPI_CR2_RXDMAEN)) + +#define SPI_CR2_SYNC	(SPI_CR2 |			\ +			 (0 << STM_SPI_CR2_TXDMAEN) |	\ +			 (0 << STM_SPI_CR2_RXDMAEN)) + +void +ao_spi_send(const void *block, uint16_t len, uint8_t spi_index) +{ +	struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + +	/* Set up the transmit DMA to deliver data */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    (void *) block, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | +			    (0 << STM_DMA_CCR_TCIE)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA -- when this is done, we know the SPI unit +	 * is idle. Without this, we'd have to poll waiting for the BSY bit to +	 * be cleared +	 */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    &spi_dev_null, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); + +	stm_spi->cr2 = SPI_CR2_DMA; + +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +} + +void +ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index) +{ +	struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + +	/* Set up the transmit DMA to deliver data */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    &value, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | +			    (0 << STM_DMA_CCR_TCIE)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA -- when this is done, we know the SPI unit +	 * is idle. Without this, we'd have to poll waiting for the BSY bit to +	 * be cleared +	 */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    &spi_dev_null, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); + +	stm_spi->cr2 = SPI_CR2_DMA; +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +} + +void +ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index) +{ +	uint8_t		*b = block; +	struct stm_spi	*stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; + +	stm_spi->cr2 = SPI_CR2_SYNC; + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	while (len--) { +		while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE))); +		stm_spi->dr = *b++; +	} +} + +void +ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) +{ +	struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + +	spi_dev_null = 0xff; + +	/* Set up transmit DMA to make the SPI hardware actually run */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    &spi_dev_null, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | +			    (0 << STM_DMA_CCR_TCIE)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA to capture data */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    block, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); + +	stm_spi->cr2 = SPI_CR2_DMA; +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); + +	/* Wait until the SPI unit is done */ +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); + +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +} + +void +ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index) +{ +	struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + +	/* Set up transmit DMA to send data */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    out, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | +			    (0 << STM_DMA_CCR_TCIE)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA to capture data */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    in, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); + +	stm_spi->cr2 = SPI_CR2_DMA; +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); + +	/* Wait until the SPI unit is done */ +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); + +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +} + +static void +ao_spi_disable_index(uint8_t spi_index) +{ +	/* Disable current config +	 */ +	switch (AO_SPI_INDEX(spi_index)) { +	case STM_SPI_INDEX(1): +		switch (spi_index) { +		case AO_SPI_1_PA5_PA6_PA7: +			stm_gpio_set(&stm_gpioa, 5, 1); +			stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); +			stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); +			break; +		case AO_SPI_1_PB3_PB4_PB5: +			stm_gpio_set(&stm_gpiob, 3, 1); +			stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); +			stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); +			break; +		} +		break; +	case STM_SPI_INDEX(2): +		switch (spi_index) { +		case AO_SPI_2_PB13_PB14_PB15: +			stm_gpio_set(&stm_gpiob, 13, 1); +			stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); +			stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); +			break; +		} +		break; +	} +} + +static void +ao_spi_enable_index(uint8_t spi_index) +{ +	switch (AO_SPI_INDEX(spi_index)) { +	case STM_SPI_INDEX(1): +		switch (spi_index) { +		case AO_SPI_1_PA5_PA6_PA7: +			stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0); +			stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0); +			stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0); +			break; +		case AO_SPI_1_PB3_PB4_PB5: +			stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0); +			stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0); +			stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0); +			break; +		} +		break; +	case STM_SPI_INDEX(2): +		switch (spi_index) { +		case AO_SPI_2_PB13_PB14_PB15: +			stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0); +			stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0); +			stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0); +			break; +		} +		break; +	} +} + +static void +ao_spi_config(uint8_t spi_index, uint32_t speed) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_info[id].stm_spi; + +	stm_spi->cr2 = SPI_CR2; +	stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |			/* Three wire mode */ +			(0 << STM_SPI_CR1_BIDIOE) | +			(0 << STM_SPI_CR1_CRCEN) |			/* CRC disabled */ +			(0 << STM_SPI_CR1_CRCNEXT) | +			(0 << STM_SPI_CR1_CRCL) | +			(0 << STM_SPI_CR1_RXONLY) | +			(1 << STM_SPI_CR1_SSM) |        		/* Software SS handling */ +			(1 << STM_SPI_CR1_SSI) |			/*  ... */ +			(0 << STM_SPI_CR1_LSBFIRST) |			/* Big endian */ +			(1 << STM_SPI_CR1_SPE) |			/* Enable SPI unit */ +			(speed << STM_SPI_CR1_BR) |			/* baud rate to pclk/4 */ +			(1 << STM_SPI_CR1_MSTR) | +			(0 << STM_SPI_CR1_CPOL) |			/* Format 0 */ +			(0 << STM_SPI_CR1_CPHA)); + +	if (spi_index != ao_spi_index[id]) { + +		/* Disable old config +		 */ +		ao_spi_disable_index(ao_spi_index[id]); + +		/* Enable new config +		 */ +		ao_spi_enable_index(spi_index); + +		/* Remember current config +		 */ +		ao_spi_index[id] = spi_index; +	} +} + +uint8_t +ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); + +	if (!ao_mutex_try(&ao_spi_mutex[id], task_id)) +		return 0; +	ao_spi_config(spi_index, speed); +	return 1; +} + +void +ao_spi_get(uint8_t spi_index, uint32_t speed) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	ao_mutex_get(&ao_spi_mutex[id]); +	ao_spi_config(spi_index, speed); +} + +void +ao_spi_put(uint8_t spi_index) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_info[id].stm_spi; + +	stm_spi->cr1 = 0; +	ao_mutex_put(&ao_spi_mutex[id]); +} + +static void +ao_spi_channel_init(uint8_t spi_index) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_info[id].stm_spi; + +	ao_spi_disable_index(spi_index); + +	stm_spi->cr1 = 0; +	(void) stm_spi->sr; +	stm_spi->cr2 = SPI_CR2_SYNC; +} + +void +ao_spi_init(void) +{ +#if HAS_SPI_1 +# if SPI_1_PA5_PA6_PA7 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); +	stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR); +	stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR); +	stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR); +# endif +# if SPI_1_PB3_PB4_PB5 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); +	stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR); +	stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR); +	stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR); +# endif +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); +	ao_spi_index[0] = AO_SPI_CONFIG_NONE; +	ao_spi_channel_init(STM_SPI_INDEX(1)); +#endif + +#if HAS_SPI_2 +# if SPI_2_PB10_PB13_PB14 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); +	stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR); +	stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR); +	stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR); +# endif +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN); +	ao_spi_index[1] = AO_SPI_CONFIG_NONE; +	ao_spi_channel_init(STM_SPI_INDEX(2)); +#endif +} diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index ce8ca456..14be5fbb 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -795,7 +795,7 @@ isr(tim7)  #define STM_ISR_TSC_POS			8  #define STM_ISR_DMA_CH1_POS		9  #define STM_ISR_DMA_CH2_3_DMA2_CH1_2_POS	10 -#define STM_ISR_DMA_CH44_5_6_7_DMA2_CH3_4_5_POS	11 +#define STM_ISR_DMA_CH4_5_6_7_DMA2_CH3_4_5_POS	11  #define STM_ISR_ADC_COMP_POS		12  #define STM_ISR_TIM1_BRK_UP_TRG_COM_POS	13  #define STM_ISR_TIM1_CC_POS		14 @@ -890,7 +890,7 @@ struct stm_dma_channel {  	vuint32_t	reserved;  }; -#define STM_NUM_DMA	6 +#define STM_NUM_DMA	5  struct stm_dma {  	vuint32_t		isr; @@ -900,7 +900,7 @@ struct stm_dma {  extern struct stm_dma stm_dma; -/* DMA channels go from 1 to 6, instead of 0 to 5 (sigh) +/* DMA channels go from 1 to 5, instead of 0 to 4 (sigh)   */  #define STM_DMA_INDEX(channel)		((channel) - 1) @@ -1042,7 +1042,7 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;  #define STM_SPI_CR1_BIDIOE		14  #define STM_SPI_CR1_CRCEN		13  #define STM_SPI_CR1_CRCNEXT		12 -#define STM_SPI_CR1_DFF			11 +#define STM_SPI_CR1_CRCL		11  #define STM_SPI_CR1_RXONLY		10  #define STM_SPI_CR1_SSM			9  #define STM_SPI_CR1_SSI			8 @@ -1063,17 +1063,43 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;  #define STM_SPI_CR1_CPOL		1  #define STM_SPI_CR1_CPHA		0 +#define STM_SPI_CR2_LDMA_TX	14 +#define STM_SPI_CR2_LDMA_RX	13 +#define STM_SPI_CR2_FRXTH	12 +#define STM_SPI_CR2_DS		8 +#define  STM_SPI_CR2_DS_4		0x3 +#define  STM_SPI_CR2_DS_5		0x4 +#define  STM_SPI_CR2_DS_6		0x5 +#define  STM_SPI_CR2_DS_7		0x6 +#define  STM_SPI_CR2_DS_8		0x7 +#define  STM_SPI_CR2_DS_9		0x8 +#define  STM_SPI_CR2_DS_10		0x9 +#define  STM_SPI_CR2_DS_11		0xa +#define  STM_SPI_CR2_DS_12		0xb +#define  STM_SPI_CR2_DS_13		0xc +#define  STM_SPI_CR2_DS_14		0xd +#define  STM_SPI_CR2_DS_15		0xe +#define  STM_SPI_CR2_DS_16		0xf  #define STM_SPI_CR2_TXEIE	7  #define STM_SPI_CR2_RXNEIE	6  #define STM_SPI_CR2_ERRIE	5 +#define STM_SPI_CR2_FRF		4 +# define STM_SPI_CR2_FRF_MOTOROLA	0 +# define STM_SPI_CR2_FRF_TI		1 +#define STM_SPI_CR2_NSSP	3  #define STM_SPI_CR2_SSOE	2  #define STM_SPI_CR2_TXDMAEN	1  #define STM_SPI_CR2_RXDMAEN	0 +#define STM_SPI_SR_FTLVL	11 +#define STM_SPI_SR_FRLVL	9 +#define STM_SPI_SR_FRE		8  #define STM_SPI_SR_BSY		7  #define STM_SPI_SR_OVR		6  #define STM_SPI_SR_MODF		5  #define STM_SPI_SR_CRCERR	4 +#define STM_SPI_SR_UDR		3 +#define STM_SPI_SR_CHSIDE	2  #define STM_SPI_SR_TXE		1  #define STM_SPI_SR_RXNE		0  | 
