So I started learning ARM-CMSIS and now I am here at learning the I2C Protocol.
So From some tutorials and guides I now have my code like this:
This is my read function:
uint8_t I2C_read(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg) {
uint8_t data;
uint32_t temp;
I2C->CR1 |= I2C_CR1_ACK;
I2C->CR1 |= I2C_CR1_START;
while (!(I2C->SR1 & I2C_SR1_SB));
I2C->DR = addr;
while (!(I2C->SR1 & I2C_SR1_ADDR));
temp = I2C->SR2;
I2C->DR = reg;
I2C->CR1 |= I2C_CR1_START;
while(!(I2C->SR1 & I2C_SR1_SB));
I2C->DR = (addr | 1);
while(!(I2C->SR1 & I2C_SR1_ADDR));
temp = I2C->SR2;
while(!(I2C->SR1 & I2C_SR1_RXNE));
I2C->CR1 &= ~I2C_CR1_ACK;
I2C->CR1 |= I2C_CR1_STOP;
data = I2C->DR;
printMSG("data: %d\r\n", data);
return data;
}
Write function:
void I2C_write(I2C_TypeDef *I2C, uint8_t dev_addr, uint8_t reg, uint8_t data) {
uint32_t temp;
I2C->CR1 |= I2C_CR1_START; // Generate Start condition
while(!(I2C->SR1 & I2C_FLAG_SB)); // Wait until the Start condition is sent
printMSG("Write Test1\r\n");
I2C->DR = dev_addr; // Send device over to the Date register
while(!(I2C->SR1 & I2C_SR1_ADDR)); // Wait until a Slave responds to the address
temp = I2C->SR2;
printMSG("Write Test2\r\n");
I2C->DR = reg; // Send internal register to write to
while (!(I2C->SR1 & I2C_SR1_TXE)); // Wait until the Transmit register is empty and thus the data is transmitted
printMSG("Write Test3\r\n");
I2C->DR = data; // Put in the data you want to write to the address
while (!(I2C->SR1 & I2C_SR1_TXE));
printMSG("Write Test4\r\n");
I2C->CR1 |= I2C_CR1_STOP;
}
And this is my I2C initialization function:
void I2C1_init(void) {
GPIO_InitTypeDef gpio_init;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
gpio_init.GPIO_Mode = GPIO_Mode_AF_OD;
gpio_init.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
//GPIOB->ODR |= (1<<6) | (1<<7) | (1<<8) | (1<<9);
GPIO_Init(GPIOB, &gpio_init);
I2C1->CR2 |= 36;
I2C1->CCR |= 180;
I2C1->TRISE |= 37;
I2C1->CR1 |= I2C_CR1_ACK;
// stretch mode enabled by default
// 7-bit addressing mode enabled by default
I2C1->CR1 |= I2C_CR1_PE;
}
It reads the data once and then just stops and I think is stuck in one of the while loops.
(Did not check which one)
I followed the documentation of the STM32F103C8T6, I have a STM32F103C8T6 BluePill board.
With the integrated CMSIS functions it does work :D
Related
Following #wovano's suggestion, I'll be boiling down the question. For the old versions of the question, see the editing history.
Overview
I'm trying to include I2C on my project (STM32F407ZGT6, MMA8452Q accelerometer) and I'm setting everything bare-metal. I'm using gschorcht library for the accelerometer functions. I currently do not have access to an osciloscope nor to an FT232H.
Problem
I am unsure if my I2C is working properly: when I try to read my Device ID, I get 0x22 instead of 0x2A*. I'm also not being able to read data in a loop. If I use if (mma845x_new_data (sensor) && mma845x_get_float_data (sensor, &data)), I never get a positive condition, and adjusting as below forces me into the Default_Handler: Infinite_Loop for debugging:
void read_data(void)
{
mma845x_float_data_t data;
if (mma845x_new_data (sensor))
{
if(mma845x_get_float_data (sensor, &data))
{
// max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
return;
}
}
printf("[not new MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
}
The Debug tab shows this trace/breakpoint trap thread:
I'm wondering if I did something wrong with my CCR or TRISE setting (I included below the calculations I'm using). I have my SYSCLK at 168MHz and APB1 at 42MHz (APB1PRESC = 4), and I'm currently testing the Standard Mode.
Things I have right
the board has all pull-up resistors properly placed
MODER and AFR are properly set
the SA0 is set to high- or low-logical level to match the device address
STOP is being sent after reading data from DR
Code
void init_gpio(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; //Port B
GPIOB->MODER |= (2U << 12U); //MMA845_SCL || PB6
GPIOB->AFR[0] |= (4U << 24U); //AF4
GPIOB->OTYPER |= (1U << 6U); //Output Type to Open Drain
GPIOB->PUPDR |= (1U << 12U); //Set to Pull-Up
GPIOB->MODER |= (2U << 14U); //MMA845_SDA || PB7
GPIOB->AFR[0] |= (4U << 28U); //AF4
GPIOB->OTYPER |= (1U << 7U); //Output Type to Open Drain
GPIOB->PUPDR |= (1U << 14U); //Set to Pull-Up
}
/*i2c_init*/
void i2c_init(I2C_TypeDef *I2Cx)
{
/*Enable clock access to I2Cs*/
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //enable I2C1
// RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; //enable I2C2
// RCC->APB1ENR |= RCC_APB1ENR_I2C3EN; //enable I2C3
RCC->APB1ENR;
/*Reset I2C*/
I2Cx->CR1 |= I2C_CR1_SWRST; /*!BUSY ON */
I2Cx->CR1 &= ~I2C_CR1_SWRST; /*!BUSY OFF*/
int CCR_VAL;
int TRISE_VAL;
int MAX_FRQ;
/*Set I2C frequency same as APB*/
MAX_FRQ = (SYSCLK/APB1PRESC)/1000000; //= 42 # max clock speed
I2Cx->CR2 &= ~msk(6,0); /*!BUSY ON*/
I2Cx->CR2 |= MAX_FRQ;
if(!MASTER_MODE){
/* Standard Mode = 100kb/s*/
/* CCR calculated by half-period of 100k
* divided by the period of the PCLK
* CCR = ((1/100'000)/2)/(1/42'000'000)
* CCR = 5000ns/~24ns = 210
*/
CCR_VAL = 210;
/* TRISE calculated by PCLK (in MHz) + 1
* TRISE = ((42'000'000/1'000'000) + 1)
* TRISE = 42 + 1 = 43
*/
TRISE_VAL = 43;
}
else
{
/*Fast Mode = 400kb/s*/
if(DUTY_MODE)
{
/*16:9 ratio*/
/* CCR calculated by half-period of 100k
* divided by the sum of the duty ratios
* divided by the period of the PCLK
* t_high = 9 * CCR * TPCLK
* t_low = 16 * CCR * TPCLK
* t_high + t_low = 25 * CCR * TPCLK
* CCR = ((1/400'000)/2) / (25/42'000'000)
* CCR = 1250ns/~595ns = 2.1 ~ 2
*/
CCR_VAL = 2;
}
else
{
//2:1 ratio
/* CCR calculated by half-period of 100k
* divided by the sum of the duty ratios
* divided by the period of the PCLK
* t_high = CCR * TPCLK
* t_low = 2 * CCR * TPCLK
* t_high + t_low = 3 * CCR * TPCLK
* CCR = ((1/400'000)/2) / (3/42'000'000)
* CCR = 1250ns/~71ns = 17.5 ~ 17
*/
CCR_VAL = 17;
}
/* TRISE calculated by PCLK (in MHz) * 0.3ms + 1
* TRISE = ((42'000'000/1'000'000)*(300/1000) + 1)
* TRISE = 42 * 0.3 + 1 = 13.6 ~ 14
*/
TRISE_VAL = 14;
}
/*Set Clock Control value*/
I2Cx->CCR |= CCR_VAL; //assuming APB1 = 42MHz, SM = True
I2Cx->CCR |= (set(DUTY_MODE,I2C_CCR_DUTY_Pos) | set(MASTER_MODE,I2C_CCR_FS_Pos));
I2Cx->TRISE |= TRISE_VAL; //assuming APB1 = 42MHz, SM = True
/*Enable I2C*/
I2Cx->CR1 |= I2C_CR1_PE;
}
void set_addr(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, int read)
{
volatile int temp;
/*Check I2C is not busy*/
while(I2Cx->SR2 & I2C_SR2_BUSY);
/*(1) Generate a START, wait for start flag*/
I2Cx->CR1 |= I2C_CR1_START;
while (!(I2Cx->SR1 & I2C_SR1_SB));
/*Transmit slave address + 'write'*/
I2Cx->DR = sAddr << 1;
/*Wait for the address flag*/
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
temp = I2Cx->SR2; //Clear address flag
/*Send memory address*/
//Make sure TXE is emtpy
while (!(I2Cx->SR1 & I2C_SR1_TXE));
I2Cx->DR = mAddr;
//Wait until transmitter is emtpy
while (!(I2Cx->SR1 & I2C_SR1_TXE));
if(read)
{
/*(2) Generate a START, wait for start flag*/
I2Cx->CR1 |= I2C_CR1_START;
while (!(I2Cx->SR1 & I2C_SR1_SB));
/*Transmit slave address + 'read'*/
I2Cx->DR = (sAddr << 1) | 1;
/*Wait for the address flag*/
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
temp = I2Cx->SR2; //Clear address flag
}
}
int i2c_burst_read(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
if(size == 0)
{
return 0;
}
uint8_t *pData = string; //points at the first byte (char) of string
set_addr(I2Cx, sAddr, mAddr, 1);
/*Enable ACK*/
I2Cx->CR1 |= I2C_CR1_ACK;
while(size > 0U)
{
if(size-- == 1)
{
/*Disable ACK*/
I2Cx->CR1 &= ~I2C_CR1_ACK;
/*Wait until the receive flag is set*/
while(!(I2Cx->SR1 & I2C_SR1_RXNE));
//"Generate STOP" was here before
/*Read data from the DR*/
*pData++ = I2Cx->DR;
break;
}
else
{
/*Wait until the receive flag is set*/
while(!(I2Cx->SR1 & I2C_SR1_RXNE));
/*Read data from the DR*/
*pData++ = I2Cx->DR;
}
}
/*Generate a STOP after receiving*/
I2Cx->CR1 |= I2C_CR1_STOP;
return 1;
}
int i2c_burst_write(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
uint8_t *pData = string; //points at the first byte (char) of string
set_addr(I2Cx, sAddr, mAddr, 0);
while(size > 0U)
{
/*Wait for transmitter to be empty*/
while(!(I2Cx->SR1 & I2C_SR1_TXE));
I2Cx->DR = *pData++;
size--;
}
/*Wait for byte transfer finished flag*/
while(!(I2Cx->SR1 & I2C_SR1_BTF));
/*Generate a STOP after writing*/
I2Cx->CR1 |= I2C_CR1_STOP;
return 1;
}
*This might be due to it being a "different brand". Although it raises some suspicion that it isn't reading all the bits (0x2A in binary is 0b0010 1010 and 0x22 is 0b0010 0010), testing it with another accelerometer gives me the value of 0x05. There's a chance bits are being lost but I'm not sure.
I figured my I2C communication was actually working! So the answer is 'Yes, my CCR and TRISE' settings were correct (at least for the 100kHz mode). To check this, I borrowed an Arduino and I pastade a simple Wire code to read and write from the line. With it, I discovered that:
I could read and write to the I2C bus (without register address)
I had problems when using the register address mAddr
The chip's ID is actually 0x2A
I was mistakenly sending to the function the address of the variable containing the memory address instead of its content (instead of mAddr = 0x1D, I was passing &mAddr as argument).
Also, #wovano guess about the HardFault was correct too. The printf was causing the crash, either because of the floating-point linkage or because it was reading an empty variable (since it wasn't getting any data).
I'm still having issues reading data from the MMA since my STATUS->ZYXDR flag never goes high (mma845x_new_data(sensor) always returns 0). My initialization is as follows, in case anyone has experience with Freescale semiconductors (library link):
#include "mma845x.h"
#define MMA845X_I2C_ADDRESS_1 0x1c // SDO pin is low
#define MMA845X_I2C_ADDRESS_2 0x1d // SDO pin is high
static mma845x_sensor_t* sensor;
void init_MMA_sensor(void)
{
sensor = mma845x_init_sensor(I2C1, MMA845X_I2C_ADDRESS_2);
mma845x_config_int_signals(sensor, mma845x_high_active, mma845x_push_pull);
mma845x_config_hpf(sensor, 0, true);
mma845x_set_scale(sensor, mma845x_scale_2_g);
mma845x_set_mode(sensor, mma845x_high_res, mma845x_odr_50, true, false); //make it active!
}
void read_data(void)
{
mma845x_float_data_t data;
if (mma845x_new_data(sensor))
{
if(mma845x_get_float_data(sensor, &data))
{
// max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\r\n",
data.ax, data.ay, data.az);
return;
}
}
printf("No new data available\r\n");
}
int main(void)
{
/*Setup*/
clock_init_168();
init_systick_MS(SYSTICK_LOAD_VAL_MS);
gpio_init();
uart_init();
i2c_init(I2C1);
init_MMA_sensor();
for(;;)
{
read_data();
delayMS(500);
}
}
But the intial question is resolved. Thanks for all your insight.
i've a homemade board with stm32l476 and w25q128jv qspi. I always use this QSPI with other stm32. I try this qspi and my software with stm32h7 and stm32f7 and all works fine, but i don't understand why with stm32l476 not work.
The pins that i use are:
GPIOE_10 --> QUADSPI_CLK
GPIOE_11 --> QUADSPI_NCS
GPIOE_12 --> QUADSPI_BK1_IO0
GPIOE_13 --> QUADSPI_BK1_IO1
GPIOE_14 --> QUADSPI_BK1_IO2
GPIOE_15 --> QUADSPI_BK1_IO3
I've a pull-up resistor for NCS to 3.3V and capacitor between 3.3V and GND.
When i write into it 256 byte of '0x23' at the posizion 0x90000000
and other 256 byte of '0xf3' at the position 0x90000100
it write this:
I use my software in this way:
init_qspi_pin();
init_qspi();
erase the qspi
qspi_write_array();
This is my software:
QSPI INIT:
unsigned char init_qspi(){
unsigned long c1;
unsigned long pass_addr;
unsigned char passchar;
unsigned long passlong;
unsigned long passlong2;
//** DEINIT **
//DISABLE QSPI
QUADSPI->CR &= ~(QUADSPI_CR_EN);
//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);
//DISABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR &= ~(RCC_AHB3ENR_QSPIEN);
//** INIT **
//ENABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR |= RCC_AHB3ENR_QSPIEN;
while ((RCC->AHB3ENR & RCC_AHB3ENR_QSPIEN) == 0)
{
}
passlong = 1;
//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);
//ENABLE QSPI PINS CLOCK
init_QSPI_pin();
QUADSPI->CR = 0x00000000;
//SET QSPI FIFO THREESHOLD (4)
passlong = 4;
QUADSPI->CR |= ((passlong-1) << 8);
//WAIT QSPI BUSY FLAG RESET
while(QUADSPI->SR & QUADSPI_SR_BUSY){
}
//SET QSPI CLOCK PRESCALER = 1 (Fahb/2)
QUADSPI->CR |= (1 << 24);
//SET SAMPLE SHIFT (1/2 CYCLE)
QUADSPI->CR |= (1 << 4);
//SET FLASH SIZE (128 Mbit)
QUADSPI->DCR |= (0x17 << 16);
//SET CS HIGH TIME BETWEEN COMMANDS (2 clk cycles --> SET CSHT = CLK CYCLES - 1 = 1)
QUADSPI->DCR |= (1 << 8);
//SET THE LEVEL THAT CLK TAKES BETWEEN COMMANDS (WHEN CS IS HIGH).
QUADSPI->DCR |= 0; //(LOW LEVEL)
//IMODE (INSTRUCTION MODE) = ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_IMODE_0;
QUADSPI->CCR &= ~(QUADSPI_CCR_ADSIZE);
QUADSPI->CCR |= QUADSPI_CCR_ADSIZE_1;
//ENABLE QSPI PERIPHERAL
QUADSPI->CR |= QUADSPI_CR_EN;
CMD_READ_QUAD_OUT = 0x6B;
CMD_ERASE_4K_SECTOR = 0x20;
CMD_QUAD_PAGE_PROGRAM = 0x32;
return 0;
}
MEMORYMAPPED:
void qspi_memory_mapped()
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;
data_register = &QUADSPI->DR;
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_QUAD_OUT;
// DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;
//FUNCTIONAL MODE (MEMORY MAPPED)
QUADSPI->CCR |= (QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0);
// SET ADDRESS TO READ
QUADSPI->AR = 0x00000000;
}
WRITE UNLOCK:
void qspi_write_unlock()
{
unsigned long passlong=0;
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION TRIG!!
QUADSPI->CCR |= CMD_WRITE_ENABLE;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
ENABLE QUAD BUS:
void qspi_enable_quad_bus(unsigned char enable)
{
unsigned long passlong=0;
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data_reg = 0x00000000;
qspi_write_unlock();
QUADSPI->DLR = 1; //SI SCRIVONO 2 BYTE
//DATA MODE = DATA ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_WRITE_REGISTER;
if (enable){
config_reg = 0x02;
}
data_reg = config_reg;
data_reg <<= 8;
data_reg |= status_reg;
// SET DATA TO SEND TRIG!!
QUADSPI->DR = data_reg;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI READ REGISTER:
unsigned char qspi_read_register(unsigned char read_reg_cmd)
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//SET INSTRUCTION
QUADSPI->CCR |= read_reg_cmd;
//FUNCTIONAL MODE (INDIRECT READ) TRIG!!
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return (unsigned char)passlong;
}
QSPI WAIT DEVICE:
void qspi_wait_device()
{
unsigned char passchar;
do
{
//WAIT UNTILL THE FLAG "WRITE IN PROGRESS" NOT RESET
passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);
}
while(passchar & 0x01);
}
QSPI READ ARRAY FROM MEMORY:
unsigned char qspi_read_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;
if (start_address + data_len > QSPI_TOTAL_SIZE)
{
return 1;
}
data_register = &QUADSPI->DR;
QUADSPI->DLR = data_len - 1;
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_QUAD_OUT;
// DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;
//FUNCTIONAL MODE (READ)
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
// SET ADDRESS TO READ TRIG!!
QUADSPI->AR = start_address;
while(data_len)
{
while(QUADSPI->SR & QUADSPI_SR_FTF)
{
if (data_len)
{
*p_data = *(__IO uint8_t *)data_register;
p_data++;
data_len--;
if (QUADSPI->SR & QUADSPI_SR_TEF)
{
//TRANSFER ERROR
return 1;
}
}
else
{
break;
}
}
}
wait_transfer_complete();
//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
QUADSPI->DLR = 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
return 0;
}
QSPI ERASE:
void qspi_erase_sector(unsigned long sector_id)
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data = 0x00000000;
unsigned long passlong;
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
switch(qspi_get_sector_size(sector_id))
{
case (4*1024):
{
QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;
break;
}
case (64*1024):
{
QUADSPI->CCR |= CMD_ERASE_64K_SECTOR;
break;
}
default:
QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;
break;
}
QUADSPI->AR = passlong;
wait_transfer_complete();
//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI WRITE LOCK:
void qspi_write_lock()
{
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION TRIG!!
QUADSPI->CCR |= CMD_WRITE_DISABLE;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI QUAD PAGE PROGRAM:
unsigned char qspi_quad_page_program(unsigned long start_address, unsigned char *p_data, unsigned long data_len){
unsigned long c1;
unsigned char passchar;
unsigned long data = 0x00000000;
volatile unsigned long *data_register;
unsigned char write_error;
unsigned long passlong;
if (data_len == 0){
return 1;
}
data_register = &QUADSPI->DR;
QUADSPI->DLR = data_len - 1; //BYTES TO WRITE
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_QUAD_PAGE_PROGRAM;
//SET QSPI ADDRESS
QUADSPI->AR = start_address;
//FUNCTIONAL MODE (WRITE)
//QUADSPI->CCR |= 0;
qspi_buffer_len = data_len;
qspi_buffer = p_data;
while(qspi_buffer_len > 0){
while(QUADSPI->SR & QUADSPI_SR_FTF){
if (qspi_buffer_len){
*(__IO uint8_t *)data_register = *qspi_buffer;
qspi_buffer++;
qspi_buffer_len--;
if (QUADSPI->SR & QUADSPI_SR_TEF){
//TRANSFER ERROR
return 1;
}
}
else
{
break;
}
}
}
while (QUADSPI->SR & QUADSPI_SR_BUSY){
c1++;
c1--;
}
//RESET FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
QUADSPI->DLR = 0;
qspi_reset_flags();
write_error = qspi_write_error_occurred();
if (write_error){
return 1;
}
qspi_wait_device();
return 0;
}
QSPI ERROR:
unsigned char qspi_write_error_occurred()
{
unsigned char passchar;
passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);
if(passchar & (0x01 << 6))
{
return 1;
}
return 0;
}
QSPI WRITE ARRAY :
unsigned char qspi_write_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{
unsigned long c1, c2, c3;
//unsigned long page_start_addr;
unsigned char write_error;
unsigned long pages_to_write;
unsigned long remaining_bytes;
unsigned char passchar;
unsigned char *data_ptr;
unsigned long qspi_idx;
if (start_address + data_len > QSPI_TOTAL_SIZE){
return 1;
}
qspi_enable_quad_bus(1);
qspi_idx = start_address;
data_ptr = p_data;
pages_to_write = data_len / QSPI_PAGE_SIZE;
for(c1=0; c1 < pages_to_write; c1++)
{
qspi_write_unlock();
if(qspi_quad_page_program(qspi_idx, data_ptr, QSPI_PAGE_SIZE)){
//ERROR
return 1;
}
qspi_write_lock();
qspi_idx += QSPI_PAGE_SIZE;
data_ptr += QSPI_PAGE_SIZE;
}
remaining_bytes = data_len % QSPI_PAGE_SIZE;
if (remaining_bytes){
qspi_write_unlock();
if(qspi_quad_page_program(qspi_idx, data_ptr, remaining_bytes)){
//ERROR
return 1;
}
qspi_write_lock();
}
return 0;
}
QSPI GET MODEL:
unsigned short qspi_get_model()
{
unsigned long device_id;
unsigned long device_info;
device_id = qspi_read_device_id();
device_id = qspi_read_device_id();
device_info = qspi_read_device_info();
if((device_id == 0x000017EF)&&
(device_info == 0x001870EF)){
return QSPI_MODEL__W25Q128JV;
}
else if((device_id == 0x00001701)&&
(device_info == 0x00182001)){
return QSPI_MODEL__S25FL128S;
}
else if((device_info == 0x0018BA20)){
return QSPI_MODEL__MIA;
}
return 0x0000;
}
QSPI INFO :
unsigned long qspi_read_device_info()
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 2;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
QUADSPI->CCR &= ~(QUADSPI_CCR_ADMODE);
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEV_INFO;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET TRANSFER FLAG
qspi_reset_flags();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI READ INFO:
unsigned long qspi_read_device_id()
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEVICE_ID;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI READ INFO:
unsigned long qspi_read_info(unsigned char instruction,unsigned char nByteToRead)
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = nByteToRead - 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//SET INSTRUCTION
QUADSPI->CCR |= instruction;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI RESET FLAG
void qspi_reset_flags()
{
unsigned char c1;
while (QUADSPI->SR & QUADSPI_SR_BUSY)
{
}
END:
QUADSPI->FCR = 0xFFFFFFFF;
}
QSPI WAIT TRASFERT COMPLETE:
void wait_transfer_complete()
{
while ((QUADSPI->SR & QUADSPI_SR_TCF) == 0)
{
}
}
Someone can help me?
Memory-mapped mode: Only read operations are allowed to the external Flash memory in this mode.
I would like to use usart communication on STM by using following code.
I take this code from website.There are two buffers that stores rx and tx values.
I can transmit data from tx buffer but when I connect GPIOB10 and GPIOB11(rx and tx pins) each other.
I couldn't see datas that I am sending from tx buffer in rx buffer.
Can you show me what am I doing wrong?
#include "stm32f4xx.h"
char RxBuf[128];
char TxBuf[128];
int cntr=0;
unsigned char WAdr,RAdr;
void SystemInitt(){
unsigned int i;
for (i=0;i<0x00100000;i++);
RCC->CFGR |= 0x00009400;
RCC->CR |= 0x00010000;
while (!(RCC->CR & 0x00020000));
RCC->PLLCFGR = 0x07402A04;
RCC->CR |= 0x01000000;
while(!(RCC->CR & 0x02000000));
FLASH->ACR = 0x00000605;
RCC->CFGR |= 0x00000002;
while ((RCC->CFGR & 0x0000000F) != 0x0000000A);
RCC->AHB1ENR |= 0x0000001F;
GPIOD->MODER = 0x55550000;
GPIOD->OSPEEDR= 0xFFFFFFFF;
}
void USART3_IRQHandler(){
volatile int Sts;
Sts=USART3->SR;
RxBuf[WAdr]=USART3->DR;
WAdr=(WAdr+1)&0x7F;
cntr++;
}
void UsartInit()
{
WAdr=0;RAdr=0;
RCC->APB1ENR|=0x00040000;
RCC->APB1RSTR|=0x00040000;
GPIOB->AFR[1]=0x07777700;
GPIOB->MODER|=0x2AA00000;
RCC->APB1RSTR&=~0x00040000;
USART3->BRR=0x1112;
USART3->CR1|=0x0000202C;
USART3->CR3|=0x80;
NVIC->ISER[1]|=0x80;
}
int main()
{
volatile int i;
UsartInit();
RCC->AHB1ENR |= 0x00200000;
RCC->AHB1RSTR|= 0x00200000;
for(i=0;i<0x1FF;i++);
RCC->AHB1RSTR&=~0x00200000;
DMA1_Stream4->M0AR=(int)&TxBuf[0];
DMA1_Stream4->PAR=(int)&USART3->DR;
DMA1_Stream4->FCR&=~0xFFFFFF40;
DMA1_Stream4->CR=(DMA1_Stream4->CR & 0xF0100000)| 0x0E000440;
for(i=0;i<128;i++) TxBuf[i]=i+1;
DMA1_Stream4->NDTR=50;
USART3->SR&=~0x40;
DMA1_Stream4->CR|=1;
while(1);
}
Thanks your advice but I didnt use cube mx . I have use direct register access method
Hi Everyone and thank you for your time.
I have been working on interfacing the STM32f446RE Nucleo board with the TLV5628 8 Bit Octal Serial DAC. I have ran into multiple issues, but the current issue has been one of two things:
1) The data and clock lines showing the exact same information
or
2) The data line showing information, but nothing on the clock line.
Regardless, the information coming out is completely incorrect.
Here is my setup code:
void SPI_INIT(void){
// Enable clocks for C
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
// SPI GPIO
GPIOC->MODER |= 2 << 3*2; // PC3 data pin
GPIOC->MODER |= 2 << 7*2; // PC7 clock pin
GPIOC->MODER |= 1 << 2*2; //pc2 load
GPIOC->MODER |= 1 << 4*2; //pc4 ldac - probably set low permanently
// Pins default to push-pull
// set all to high speed
GPIOC->OSPEEDR |= (3 << 2*2) | (3 << 3*2) | (3 << 4*2) | (3 << 7*2);
GPIOC->AFR[0] |= 5<< 6*2; // Alt func 5 pc3 - SPI2
GPIOC->AFR[0] |= 5 << 7*2; // Alt func 5 pc7 - SPI2
// SPI Setup
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // Enable SPI Clock
RCC->APB1RSTR |= RCC_APB1RSTR_SPI2RST; // reset SPI2
RCC->APB1RSTR &= ~RCC_APB1RSTR_SPI2RST;// clear the reset
// Control Register 1
SPI2->CR1 &= ~SPI_CR1_SPE; // Disable SPI
SPI2->CR1 |= SPI_CR1_MSTR; // master mode
SPI2->CR1 &= ~SPI_CR1_RXONLY; // transmit, 0 == full duplex
SPI2->CR1 &= ~SPI_CR1_DFF; // 8 bit format
SPI2->CR1 &= ~SPI_CR1_LSBFIRST; // MSB first
SPI2->CR1 &= ~SPI_CR1_CPOL;// low polarity, so 0 when idle
SPI2->CR1 |= 4 << 3; // (180M/4)/32 = 1.41 MHz
SPI2->CR1 |= SPI_CR1_CPHA; // first edge, look in data sheet
//Questionable settings
// Biderectional data line
SPI2->CR1 |= SPI_CR1_BIDIMODE; // 1/17/2019 --> Check to see if this fixes something
SPI2->CR1 |= SPI_CR1_BIDIOE; // idk if i need this
// CRC Polynomial Register
SPI2->CRCPR = 10;
// Control Register 2
SPI2->CR2 |= 1<<2; // SS output enabled
SPI2->CR1 |= SPI_CR1_SPE; // enable, has to be last
}
And here is my SPI Write code:
void SPI_Write(int dacSelect, int adcData){
while((SPI2->SR & SPI_SR_TXE) != 0);
GPIOC->ODR |= 1 << 2; // load set high to read data
SPI2->DR = dacArray[dacSelect]; // send address
SPI2->DR = adcData; // send adc data
while((SPI2->SR & SPI_SR_BSY) == SPI_SR_BSY);
GPIOC->ODR &= ~(1 << 2); // Send load low to load data
Delay(10); // short delay
GPIOC->ODR |= 1 << 2;
}
You can use STMCubeMX to generate codes for STM microprocessors and boards. Following code blocks are generated from STM32ubeMX for STM32F4. You should change baudrate for your sensor.
SPI_HandleTypeDef hspi;
SPI_HandleTypeDef SpiHandle;
void Spi_Initialize(void)
{
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPI2;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
while(1){};
}
}
void Spi_Read(void )
{
uint8_t SpiData[2];
uint8_t tempmessage = 8;
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_TransmitReceive(&hspi,&tempmessage,SpiData,2,5000); // Read Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}
void Spi_Write(uint8_t *Data, uint8_t size)
{
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_Transmit(&hspi, Data, size, 5000); // Write Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}
I want to create firmware to stm32f4 discovery which flashes the lights, when the board moves. But SPI_I2S_ReceiveData always returns 0xff or 0x00. I think the problem is in my SPI initialization but I do not know where exactly it is.
Here is my code.
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_spi.h>
#include <stm32f4xx_i2c.h>
void InitLEDs(void);
void InitSPI(void);
void Delay(int iTicks);
void DiodeFlash(void);
unsigned short ReadACCELEROMETER(void);
unsigned char WriteSPI(unsigned char cbData);
int main(void)
{
unsigned short cbPrevRead = 0;
unsigned short cbCurrentRead = 0;
InitLEDs();
InitSPI();
while(1)
{
cbCurrentRead = ReadACCELEROMETER();
if (cbCurrentRead != cbPrevRead)
{
DiodeFlash();
cbPrevRead = cbCurrentRead;
}
}
}
void InitLEDs(void)
{
GPIO_InitTypeDef PortD;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
PortD.GPIO_Mode = GPIO_Mode_OUT;
PortD.GPIO_OType = GPIO_OType_PP;
PortD.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortD.GPIO_Speed = GPIO_Speed_100MHz;
PortD.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOD, &PortD);
}
void InitSPI(void)
{
GPIO_InitTypeDef PortA;
GPIO_InitTypeDef PortE;
SPI_InitTypeDef SPI1Conf;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
PortA.GPIO_Mode = GPIO_Mode_AF;
PortA.GPIO_OType = GPIO_OType_PP;
PortA.GPIO_Speed = GPIO_Speed_50MHz;
PortA.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortA.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &PortA);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
PortE.GPIO_Mode = GPIO_Mode_OUT;
PortE.GPIO_OType = GPIO_OType_PP;
PortE.GPIO_Speed = GPIO_Speed_50MHz;
PortE.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortE.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOE, &PortE);
GPIOE->ODR = 0x0008; // Disable CS
SPI1Conf.SPI_DataSize = SPI_DataSize_8b;
SPI1Conf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
SPI1Conf.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI1Conf.SPI_FirstBit = SPI_FirstBit_MSB; // ACCELEROMETER PROTOCOL
SPI1Conf.SPI_Mode = SPI_Mode_Master;
SPI1Conf.SPI_CPHA = SPI_CPHA_2Edge;
SPI1Conf.SPI_CPOL = SPI_CPOL_High;
SPI1Conf.SPI_CRCPolynomial = 7;
SPI1Conf.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPI1, &SPI1Conf);
SPI_Cmd(SPI1, ENABLE);
WriteSPI(0x23); WriteSPI(0xc9);
WriteSPI(0x20); WriteSPI(0x97);
WriteSPI(0x24); WriteSPI(0x00);
WriteSPI(0x10); WriteSPI(0x00);
WriteSPI(0x11); WriteSPI(0x00);
WriteSPI(0x12); WriteSPI(0x00);
}
void Delay(int iTicks)
{
while ((iTicks--) > 0);
}
void DiodeFlash(void)
{
GPIO_Write(GPIOD, 1UL << 12);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 13);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 14);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 15);
Delay(100000);
GPIO_Write(GPIOD, 0x0000);
}
unsigned short ReadACCELEROMETER(void)
{
unsigned short nAxisX = 0x0000;
unsigned short nAxisY = 0x0000;
unsigned short nAxisZ = 0x0000;
unsigned char cbAddress = 0x80;
//**********************************************************
// Forming X Value
WriteSPI(cbAddress | 0x0f);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2A);
nAxisX |= WriteSPI(0x00) << 8;
//**********************************************************
// Forming Y Value
WriteSPI(cbAddress | 0x2B);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2C);
nAxisX |= WriteSPI(0x00) << 8;
//**********************************************************
// Forming Z Value
WriteSPI(cbAddress | 0x2D);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2E);
nAxisX |= WriteSPI(0x00) << 8;
return nAxisX ^ nAxisY ^ nAxisZ;
}
unsigned char WriteSPI(unsigned char cbData)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // Enable CS
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
SPI_I2S_SendData(SPI1, cbData);
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
cbResult = SPI_I2S_ReceiveData(SPI1);
GPIOE->ODR = 0x0008; // Disable CS
return cbResult;
}
First, you don't specify your accelerometer. I can guess, that it is ST LISxx.
In this case, there is incorrect data transfer to accelerometer.
Correct write sequence:
- activate chipselect
- write register number
- write register value
- deactivate chipselect
Use similar sequence to read each register.
Next, ST not recommend your algo for low-level SPI transfer:
Do not use the BSY flag to handle each data transmission or reception. It is better to use the TXE and RXNE flags instead
(see Reference manual). Use simply
SPIx->DR = out;
while (!(SPIx->SR & SPI_SR_RXNE)) ;
return SPIx->DR;
Also, i am working with LIS3DH with CPOL=0 & CPHA = 0 SPI settings (i don't know, how it will work with your CPOL=1, CPHA=1).
Hint: to check SPI communication, try to read WHO_AM_I register - it is alawys enabled and always have known value.
It is beacuse you writes address of register, after deselects your device, so wrote address is clean up. In this case you must do something like this.
unsigned char WriteSPI(unsigned char cbData)
{
unsigned char cbResult = 0x00;
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
SPI_I2S_SendData(SPI1, cbData);
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
cbResult = SPI_I2S_ReceiveData(SPI1);
return cbResult;
}
unsigned char WriteReg(unsigned char cbAddress, unsigned char cbData)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // select device
WriteSPI(cbAddress);
cbResult = WriteSPI(cbData);
GPIOE->ODR = 0x0008; // deselect device
return cbResult;
}
unsigned char ReadReg(unsigned char cbAddress)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // select device
WriteSPI(cbAddress);
cbResult = WriteSPI(0x00);
GPIOE->ODR = 0x0008; // deselect device
return cbResult;
}
There is nothing wrong with your SPI initialization. The main mistake is in writing register addresses. You must not deselect device before reading register values, instead you must perform write address - reading values in one batch. It mean
Select device.
Write register address.
Read register value.
Deselect device.