I am trying to connect to an RFM95W module using the Cortex-M3 Blue Pill from ST.
I am an embedded novice but know my way around linux, so I used the below code on an Rpi3 to connect to the chip and read the version from the REG_VERSION register at address 0x42
and was able to get the correct value of 0x12
.
int main()
{
...
wiringPiSetup();
pinMode(rfmodule->pin_rst, OUTPUT);
wiringPiSPISetup(SPI_CHANNEL, SPI_RATE);
digitalWrite(rfmodule->pin_rst, LOW);
delay(100);
digitalWrite(rfmodule->pin_rst, HIGH);
delay(100);
uint8_t version = read_register(REG_VERSION);
}
uint8_t
read_register(uint8_t addr)
{
uint8_t spibuf[2];
spibuf[0] = addr & 0x7F;
spibuf[1] = 0x00;
wiringPiSPIDataRW(SPI_CHANNEL, spibuf, 2);
return spibuf[1];
}
I have been working to port this code to work on the blue pill by reading the ref manual (rm0008), using CMSIS to init SPI1 and this online tutorial. My code is
#include "stm32f10x.h"
#include "stm32f10x_spi.h"
#define SYS_CLOCK_HZ 9000000U
#define REG_VERSION 0x42
void dummy(unsigned int i);
void dummy(unsigned int i)
{
while (i > 0)
{
i--;
}
}
void blink(void)
{
if ( (GPIOC->ODR & (1U << 13)) == 0U )
{
// turn on
GPIOC->ODR |= (1U << 13);
}
else
{
// turn off
GPIOC->ODR &= ~(1U << 13);
}
dummy(1000000U);
}
int main ( void )
{
SPI_InitTypeDef SPI_InitStruct;
SPI_StructInit(&SPI_InitStruct);
// enable ports A and C and SPI1
RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_SPI1EN);
//config PC13 as digital output
GPIOC->CRH &= ~(GPIO_CRH_MODE13); //PC13
GPIOC->CRH |= GPIO_CRH_MODE13_0; //PC13
// SCK/PA5 -- Alternate function push-pull CNF 10 -- MODE 11
// MOSI/PA7 -- Alternate function push-pull CNF 10 -- MODE 11
// MISO/PA6 -- Input floating / Input pull-up CNF 01 -- MODE 00
// NSS/PA3 -- Alternate function push-pull CNF 10 -- MODE 11
// RST/PA4 -- Output mode, max speed 10 MHz CNF 01 -- MODE 00
// leave MISO in RESET STATE
// set CNF 10 for A4, A5, and A7
GPIOA->CRL |= (GPIO_CRL_MODE4 | GPIO_CRL_MODE5| GPIO_CRL_MODE7);
// set MODE 11 for A4, A5, and A7
GPIOA->CRL |= (GPIO_CRL_CNF5_0 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF4_0);
// reset pin is generic output pin
GPIOA->CRL |= ~(GPIO_CRL_MODE3);
GPIOA->CRL |= GPIO_CRL_CNF3_1;
// disable slave by setting NSS to high
GPIOA->ODR |= (1U << 4U);
/*
In input mode (MODE[1:0]=00):
00: Analog mode
01: Floating input (reset state)
10: Input with pull-up / pull-down
11: Reserved
In output mode (MODE[1:0] > 00):
00: General purpose output push-pull
01: General purpose output Open-drain
10: Alternate function output Push-pull
11: Alternate function output Open-drain
*/
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
while(1){
// enable slave by setting NSS low
GPIOA->ODR |= (0U << 4U);
dummy(500);
// reset radio with PA3
GPIOA->ODR |= (0U << 3U);
dummy(500);
GPIOA->ODR |= (1U << 3U);
dummy(500);
// Write data to be transmitted to the SPI data register
SPI1->DR = REG_VERSION & 0x7F;
// // Wait until transmit complete
while (!(SPI1->SR & (SPI_I2S_FLAG_TXE)));
// Wait until receive complete
while (!(SPI1->SR & (SPI_I2S_FLAG_RXNE)));
// Wait until SPI is not busy anymore
while (SPI1->SR & (SPI_I2S_FLAG_BSY));
uint32_t tmp = SPI1->DR;
// disable slave by setting NSS to high
GPIOA->ODR |= (1U << 4U);
blink();
}
return(0);
}
Stepping through with gdb on Sublime I get all the way to the temp variable so I know the SPI_I2S_FLAG_TXE
and SPI_I2S_FLAG_RXNE
are set. However the value 0
is in the DR
register and not the expected 0x12
.
I double checked the wiring and now I am looking to the community to see if someone can spot a problem in the code that I am just not seeing?
GPIOA->ODR |= (0U << 4U);
andGPIOA->ODR |= (0U << 3U);
does nothing, clear a bit by writingGPIOA->ODR &= ~(0u << 4u);
or use theGPIOA->BSRR
\$\endgroup\$