I use a STM32 connected with SPI to a MCP23S17 16 bit I/O port expander.
I want to make all 16 I/0 pins as output and just making them all LOW or HIGH.
I used an oscilloscope to check is SPI transmit the signals right, and it does.
The only thing is that on the I/O pins I get around 0.4V. Not 5V.
Sometimes I get a value of 1.4V but it goes away, weird thing...
Can somebody check my code and tell me where is my mistake? I am pretty sure I did the code wrong somewhere.
MCP23S17.h:
#ifndef INC_MCP23S17_H_
#define INC_MCP23S17_H_
#include "stm32f1xx_hal_conf.h"
extern SPI_HandleTypeDef hspi2;
void MCP23S17_SPI_Write(uint8_t reg_addr, uint8_t data);
uint8_t MCP23S17_SPI_Read(uint8_t data);
#define CS_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
#define CS_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
#define MCP23S17_AAA ((uint8_t)0x0E)
#define MCP23S17_ADDRESS ((uint8_t)0x40)
#define MCP23S17_W ((uint8_t)0x00)
#define MCP23S17_R ((uint8_t)0x01)
#define MCP23S17_IODIRA ((uint8_t)0x00)
#define MCP23S17_IPOLA ((uint8_t)0x02)
#define MCP23S17_GPINTENA ((uint8_t)0x04)
#define MCP23S17_DEFVALA ((uint8_t)0x06)
#define MCP23S17_INTCONA ((uint8_t)0x08)
#define MCP23S17_IOCONA ((uint8_t)0x0A)
#define MCP23S17_GPPUA ((uint8_t)0x0C)
#define MCP23S17_INTFA ((uint8_t)0x0E)
#define MCP23S17_INTCAPA ((uint8_t)0x10)
#define MCP23S17_GPIOA ((uint8_t)0x12)
#define MCP23S17_OLATA ((uint8_t)0x14)
#define MCP23S17_IODIRB ((uint8_t)0x01)
#define MCP23S17_IPOLB ((uint8_t)0x03)
#define MCP23S17_GPINTENB ((uint8_t)0x05)
#define MCP23S17_DEFVALB ((uint8_t)0x07)
#define MCP23S17_INTCONB ((uint8_t)0x09)
//#define MCP23S17_IOCONB ((uint8_t)0x0B)
#define MCP23S17_GPPUB ((uint8_t)0x0D)
#define MCP23S17_INTFB ((uint8_t)0x0F)
#define MCP23S17_INTCAPB ((uint8_t)0x11)
#define MCP23S17_GPIOB ((uint8_t)0x13)
#define MCP23S17_OLATB ((uint8_t)0x15)
//#define MCP23S17_INT_ERR ((uint8_t)255)
//#define BANK ((uint8_t)0x80) //bit 7 of IOCON
//#define MIRROR ((uint8_t)0x40) //bit 6 of IOCON
//#define SEQOP ((uint8_t)0x20) //bit 5 of IOCON
//#define DISSLW ((uint8_t)0x10) //bit 4 of IOCON
//#define HAEN ((uint8_t)0x08) //bit 3 of IOCON
//#define ODR ((uint8_t)0x04) //bit 2 of IOCON
//#define INTPOL ((uint8_t)0x02) //bit 1 of IOCON
//#define unused ((uint8_t)0x00) //bit 0 of IOCON
//-----------------------
#define MCP23S17_MODERA_W(x) MCP23S17_SPI_Write(MCP23S17_IODIRA, ((uint8_t)x))
#define MCP23S17_MODERA_R() MCP23S17_SPI_Read(MCP23S17_IODIRA)
#define MCP23S17_IPOLA_W(x) MCP23S17_SPI_Write(MCP23S17_IPOLA, ((uint8_t)x))
#define MCP23S17_ODRA_W(x) MCP23S17_SPI_Write(MCP23S17_OLATA, ((uint8_t)x))
#define MCP23S17_ODRA_R() MCP23S17_SPI_Read(MCP23S17_OLATA)
#define MCP23S17_IDRA_R() MCP23S17_SPI_Read(MCP23S17_GPIOA) // Reflect the value of the port A
#define MCP23S17_PUDA_W(x) MCP23S17_SPI_Write(MCP23S17_GPPUA, ((uint8_t)x))
#define MCP23S17_PUDA_R() MCP23S17_SPI_Read(MCP23S17_GPPUA)
#define MCP23S17_SETUP_W(x) MCP23S17_SPI_Write(MCP23S17_IOCONA, ((uint8_t)x))
#define MCP23S17_SETUP_R() MCP23S17_SPI_Read(MCP23S17_IOCONA))
#define MCP23S17_MODERB_W(x) MCP23S17_SPI_Write(MCP23S17_IODIRB, ((uint8_t)x))
#define MCP23S17_MODERB_R() MCP23S17_SPI_Read(MCP23S17_IODIRB)
#define MCP23S17_IPOLB_W(x) MCP23S17_SPI_Write(MCP23S17_IPOLB, ((uint8_t)x))
#define MCP23S17_ODRB_W(x) MCP23S17_SPI_Write(MCP23S17_OLATB, ((uint8_t)x))
#define MCP23S17_ODRB_R() MCP23S17_SPI_Read(MCP23S17_OLATB)
#define MCP23S17_IDRB_R() MCP23S17_SPI_Read(MCP23S17_GPIOB) // Reflect the value of the port B
#define MCP23S17_PUDB_W(x) MCP23S17_SPI_Write(MCP23S17_GPPUB, ((uint8_t)x))
#define MCP23S17_PUDB_R() MCP23S17_SPI_Read(MCP23S17_GPPUB)
//-----------------------
void GPIO_Write_Pins(uint16_t);
void GPIO_Expander_Init();
void MCP23S17_SPI_Write(uint8_t reg_addr, uint8_t data);
#endif /* INC_MCP23S17_H_ */
MCP23S17.c
#include "main.h"
#include "MCP23S17.h"
void MCP23S17_SPI_Write(uint8_t reg_addr, uint8_t data)
{
uint8_t pBuff[3];
pBuff[0] = MCP23S17_ADDRESS|MCP23S17_AAA|MCP23S17_W; //optocode that contain 0100 + 111 + 0 (read command)
pBuff[1] = reg_addr; // register address
pBuff[2] = data; // the value that is modified on the register, check datasheet
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_SPI_Transmit_IT(&hspi2, pBuff, 3); //transmit on the spi2 the optocode, register adress and the value for the register
for(uint32_t i = 0; i < 85; i++) //delay
{}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
}
void GPIO_Expander_Init()
{
MCP23S17_SETUP_W(0x00);
MCP23S17_MODERA_W(0x00);
MCP23S17_MODERB_W(0x00);
MCP23S17_PUDA_W(0x00);
MCP23S17_PUDB_W(0x00);
//MCP23S17_IPOLA_W(0x00);
//MCP23S17_IPOLB_W(0x00);
}
void GPIO_Write_Pins(uint16_t dataspi)
{
//16 to 8 and 8
uint8_t data_half[2];
data_half[0]=*((uint8_t*)&(dataspi)+1); //split the first half of the data
data_half[1]=*((uint8_t*)&(dataspi)+0); //split the second half of the data
MCP23S17_ODRA_W(data_half[0]); //first half
MCP23S17_ODRB_W(data_half[1]); //second half
}
and in main.c
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
GPIO_Expander_Init();
GPIO_Write_Pins(0xFFFF);
while(1)
{
}
The only thing is that on the I/O pins I get around 0.4V
This is likely because GPIOs are not initialized.
You also have a different problem to deal with.
for(uint32_t i = 0; i < 85; i++) //delay
{}
This loop is very likely to be optimize away by the compiler. This is because, it doesn't do anything.
There are more sophisticated ways of generating delays in a microcontroller. The best possible solution would be to use a timer module.
So coming back with the solution, the code was good, 2 first gpio expanders that I tried were purely burned. For a much shorter working code just comment here asking for it. Thank everyone for advices cause I took them in consideration in the final form of code.
Related
hello i am new with the stm32 board i am trying to toggle the user led that is connected to port A pin 5 (nucleo l476rg board) , I wrote this program from scratch using structure types but unfortunately the led is not blinking … I double checked all the addresses because i tried it without the structures and it worked , can any one tell me what’s the problem here ? here's the code:
// Port A
// pin 5
#include <stdint.h>
#define periph_base (0x40000000UL)
#define ahb2_offset (0x08000000UL)
#define ahb2_base (periph_base + ahb2_offset)
#define ahb1_offset (0x20000UL)
#define ahb1_base (periph_base + ahb1_offset)
#define gpioa_offset (0x000000UL)
#define gpioa_base (ahb2_base + gpioa_offset)
#define rcc_offset (0X1000UL)
#define rcc_base (ahb1_base + rcc_offset)
#define rcc_ahb2enr_offset (0x4CUL)
#define rcc_ahb2enr (*(volatile unsigned int *)(rcc_base +rcc_ahb2enr_offset))
#define gpioa_moder_offset (0x00UL)
#define gpioa_moder (*(volatile unsigned int*)(gpioa_base +gpioa_moder_offset))
#define odr_offset (0X14UL)
#define odr (*(volatile unsigned int*)(gpioa_base + odr_offset))
#define gpioa_en (1U<<0)
#define pin5 (1U<<5)
#define led_pin pin5
typedef struct
{
volatile uint32_t MODER;
volatile uint32_t DUMMY[4];
volatile uint32_t ODR;
}gpio_Typedef;
typedef struct
{
volatile uint32_t DUMMY[16];
volatile uint32_t AHB2ENR;
}rcc_Typedef;
#define RCC ((rcc_Typedef*) rcc_base)
#define GPIOA ((gpio_Typedef*) gpioa_base)
int main(void)
{
RCC->AHB2ENR |= gpioa_en;
GPIOA->MODER |= (1U<<10);
GPIOA->MODER &=~ (1U<<11);
while(1)
{
GPIOA->ODR ^= led_pin;
for(long int i =0; i<100000;i++){}
}
}
It appears that i had the wrong reference manual , in the rcc_Typedef Structure the dummy array should have 19 as size not 16 , there are 19 registers before the rcc_ahb2enr .
Hi i am working on a school project where I'm supposed to output temperature values on an Oled display.
i have managed to do it with Arduino Code so i know that the sensor and display works, but the code has to be written in Atmel studio in pure embedded C for the project.
I'm not sure what I'm doing wrong and what I'm am doing right.
I'm struggling with C code and the I2C protocol.
i have done a lot of research on the subject but evertime i seem to only find arduino tutorials, or theory related posts.
I'm totally new to programming.
anyway this is the code i have come up with so far.
the txt i have written for the display is displayed. everthing works as it should except for the temperatur values:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "OLED.h"
#include "ATmega_Init.h"
#include "i2c_master.h"
//From Arduino Adafruit_MLX90614 lib
// RAM
#define MLX90614_RAWIR1 0x04
#define MLX90614_RAWIR2 0x05 //Important for reading out
#define MLX90614_TA 0x06
#define MLX90614_TOBJ1 0x07
#define MLX90614_TOBJ2 0x08
// EEPROM
#define MLX90614_TOMAX 0x20
#define MLX90614_TOMIN 0x21
#define MLX90614_PWMCTRL 0x22
#define MLX90614_TARANGE 0x23
#define MLX90614_EMISS 0x24
#define MLX90614_CONFIG 0x25
#define MLX90614_ADDR 0x0E
#define MLX90614_ID1 0x3C
#define MLX90614_ID2 0x3D
#define MLX90614_ID3 0x3E
#define MLX90614_ID4 0x3F
#define SLAVE_ADDRESS 0x5A
int main(void)
{
//uint8_t test_recieve[2];
uint16_t test_recieve_high; //To receive the high byte
uint16_t test_recieve_low; //To receive the low byte
init_atmega_setup();
initDisplay();
i2c_init();
clsDisplay();
strFont5XY("Floor Unit",25,3);
_delay_ms(2000);
clsDisplay();
//uint8_t receive_command = 0x00; //Needs the receive command,
definitely not just 0x00
while(1){
i2c_start(SLAVE_ADDRESS);
i2c_write(MLX90614_TOBJ1);
i2c_start(SLAVE_ADDRESS);
test_recieve_high = i2c_read_ack();
i2c_start(MLX90614_TOBJ1);
test_recieve_high = ((uint8_t)i2c_read_ack())<<8;
test_recieve_high |= i2c_read_ack();
i2c_stop();
i2c_start(SLAVE_ADDRESS);
i2c_write(MLX90614_TOBJ1);*/
i2c_start(MLX90614_TOBJ1);
test_recieve_low = ((uint8_t)i2c_read_ack())<<8;
test_recieve_low |= i2c_read_ack();
i2c_stop();
intFont5XY(test_recieve_low,1,0);
intFont5XY(test_recieve_high,1,1);
_delay_ms(1000);
};
};
I'm using an Atmega168 I'm attempting to use I2C with my PCA9685 Servo driver.
I'm using this I2C library: https://github.com/g4lvanix/I2C-master-lib
I'm attempting to start the I2C connection with my PCA9685 (Address: 0x41).
For some reason the I2C Library is bouncing back an error because the acknowledge bit isn't being sent. What is wrong here? My SDA and SCL pins are hooked up to 10k pull up resistors, and they are connected to the PCA9685 correctly. Yet it still isn't working. Could it be my PCA9685 chip? I also know the address is 0x41 because I manually bridged an address connection to assign that address.
Here is my code:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include "i2c.h"
#define SERVO_MIN 1000
#define SERVO_MAX 2000
#define SERVO_MID 1500
#define PCA9685_ADDR 0x40
#define PCA9685_MODE1 0x0
#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9
#define LED PB0
#define LED_DDR DDRB
#define LED_PORT PORTB
#define DELAYTIME 200
#define setBit(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit))
#define clearBit(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit))
#define toggleBit(sfr, bit) (_SFR_BYTE(sfr) ^= (1 << bit))
void setupController();
void setServo(uint8_t id, uint8_t start, uint8_t stop);
int main(void)
{
setBit(LED_DDR, LED);
clock_prescale_set(clock_div_1);
i2c_init();
uint8_t err = i2c_start(0x41);
while(err == 1) {
setBit(LED_PORT, LED);
uint8_t err = i2c_start(0x41);
}
clearBit(LED_PORT, LED);
while(1) {
}
return 0;
}
Thank you in advance!
// Created by lenovo on 8/27/2017.
//
#ifndef UART_UART_CFG_H
#define UART_UART_CFG_H
#define UART_BaudRate 1200 //9600UL
#define CLK 16
#define UART_Parity NONE
#define UART_TX EN_TX
#define UART_RX EN_RX
#define UART_STARTBITS 1
#define UART_STOPBITS 1
#define UART_DATABITS EightBits
#endif //UART_UART_CFG_H
This is the error "called object is not a function or pointer"
and this my private file that have all word's addresses inside the config file. The first file:
//
// Created by lenovo on 8/27/2017.
//
#ifndef UART_UART_PRIV_H
#define UART_UART_PRIV_H
/* Main PINS */
#define UCSRA *((volatile u8 *)0x2B)
#define UCSRB *((volatile u8 *)0x2A)
#define UCSRC *((volatile u8 *)0x40)
#define UBRRL *((volatile u8 *)0x29)
#define UBRRH *((volatile u8 *)0x40)
#define UDR *((volatile u8 *)0x2C)
/* END Main PINS */
#define NONE 0x00
#define twoBit 0x08
#define oneBit 0x00
/* Bits */
#define fiveBits 0x00
#define SixBits 0x02
#define SevenBits 0x04
#define EightBits 0x06
/* End Bits */
#define DIS 0 // Disable
#define EN 1 // Enable
#define UART_9600 9600UL
#endif //UART_UART_PRIV_H
Private file that have some addresses for my Microcontroller ATmega16. Moreover, my config file is reference to private file; which have keys that defined in private. For example, in UART_Partit I wrote NONE and NONE address defined in private but it shows error
You need to include your file with declarations.
#ifndef UART_UART_CFG_H
#define UART_UART_CFG_H
#include "uart_priv.h"
#define UART_BaudRate 1200 //9600UL
#define CLK 16
#define UART_Parity NONE
#define UART_TX EN_TX
#define UART_RX EN_RX
#define UART_STARTBITS 1
#define UART_STOPBITS 1
#define UART_DATABITS EightBits
#endif //UART_UART_CFG_H
and there are no EN_TX or EN_RX defines for these constants in your second file.
I have following chunk of code:
// **** CONTROL REGISTER 4 SETUP ****
ctrl|=(uint8_t)(LIS3DSH_InitStruct->CR4_Odr);
if(LIS3DSH_InitStruct->CR4_Bdu)
ctrl|=(1<<LIS3DSH_CR4_BDU_POSITION);
if(LIS3DSH_InitStruct->CR4_Zen)
ctrl|=(1<<LIS3DSH_CR4_Z_AXIS_POSITION);
if(LIS3DSH_InitStruct->CR4_Yen)
ctrl|=(1<<LIS3DSH_CR4_Y_AXIS_POSITION);
if(LIS3DSH_InitStruct->CR4_Xen)
ctrl|=(1<<LIS3DSH_CR4_X_AXIS_POSITION);
LIS3DSH_Write(&ctrl,
LIS3DSH_CTRL_REG4_ADDR,
sizeof(ctrl));
delay(1000000);
// **** END OF CONTROL REGISTER 4 SETUP ****
Now, I am pretty sure these if clauses (since this is embedded world) can be replaced with bit manipulation techniques, can someone show me how? I know this is pretty stupid question, but I've simply forgot these things ...
Here is header file with structure:
#ifndef __STM32F4_DISCOVERY_LIS3DS_H
#define __STM32F4_DISCOVERY_LIS3DS_H
#include "stm32f4xx.h"
#define LIS3DSH_CTRL_REG1_ADDR 0x21
#define LIS3DSH_CTRL_REG2_ADDR 0x22
#define LIS3DSH_CTRL_REG3_ADDR 0x23
#define LIS3DSH_CTRL_REG4_ADDR 0x20
#define LIS3DSH_CTRL_REG5_ADDR 0x24
#define LIS3DSH_CTRL_REG6_ADDR 0x25
#define LIS3DSH_INFO1_REG_ADDR 0x0d
#define LIS3DSH_INFO2_REG_ADDR 0x0e
#define LIS3DSH_WHOAMI_REG_ADDR 0x0f
#define LIS3DSH_STATUS_REG_ADDR 0x27
#define LIS3DSH_TEMPERATURE_REG_ADDR 0x0c
#define LIS3DSH_OUT_X_L_REG_ADDR 0x28
#define LIS3DSH_OUT_X_H_REG_ADDR 0x29
#define LIS3DSH_OUT_Y_L_REG_ADDR 0x2a
#define LIS3DSH_OUT_Y_H_REG_ADDR 0x2b
#define LIS3DSH_OUT_Z_L_REG_ADDR 0x2c
#define LIS3DSH_OUT_Z_H_REG_ADDR 0x2d
#define LIS3DSH_FLAG_ZXYOR ((uint8_t)0x00)
#define LIS3DSH_FLAG_ZOR ((uint8_t)0x01)
#define LIS3DSH_FLAG_YOR ((uint8_t)0x02)
#define LIS3DSH_FLAG_XOR ((uint8_t)0x03)
#define LIS3DSH_FLAG_ZXYDA ((uint8_t)0x04)
#define LIS3DSH_FLAG_ZDA ((uint8_t)0x05)
#define LIS3DSH_FLAG_YDA ((uint8_t)0x06)
#define LIS3DSH_FLAG_XDA ((uint8_t)0x07)
#define DEVICE_ID ((uint8_t)0x3f)
#define LIS3DSH_SM1_INT_TO_PIN_INT1 ((uint8_t)0x00)
#define LIS3DSH_SM1_INT_TO_PIN_INT2 ((uint8_t)0x01)
#define LIS3DSH_SM1_DISABLE ((uint8_t)0x00)
#define LIS3DSH_SM1_ENABLE ((uint8_t)0x01)
#define LIS3DSH_SM2_INT_TO_PIN_INT1 ((uint8_t)0x00)
#define LIS3DSH_SM2_INT_TO_PIN_INT2 ((uint8_t)0x01)
#define LIS3DSH_SM2_DISABLE ((uint8_t)0x00)
#define LIS3DSH_SM2_ENABLE ((uint8_t)0x01)
#define LIS3DSH_CR3_DREN_TO_INT1_DISABLE ((uint8_t)0x00)
#define LIS3DSH_CR3_DREN_TO_INT1_ENABLE ((uint8_t)0x01)
#define LIS3DSH_CR3_IEA_ACTIVE_LOW ((uint8_t)0x00)
#define LIS3DSH_CR3_IEA_ACTIVE_HIGH ((uint8_t)0x01)
#define LIS3DSH_CR3_IEL_LATCHED ((uint8_t)0x00)
#define LIS3DSH_CR3_IEL_PULSED ((uint8_t)0x01)
#define LIS3DSH_CR3_INT2_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR3_INT2_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR3_INT1_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR3_INT1_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR3_VFILT_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR3_VFILT_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR3_NO_SOFT_RESET ((uint8_t)0x00)
#define LIS3DSH_CR3_SOFT_RESET ((uint8_t)0x01)
#define LIS3DSH_CR4_ODR_POWER_DOWN ((uint8_t)0x00)
#define LIS3DSH_CR4_ODR_3f125HZ ((uint8_t)0x01)
#define LIS3DSH_CR4_ODR_6f25HZ ((uint8_t)0x02)
#define LIS3DSH_CR4_ODR_12f5HZ ((uint8_t)0x03)
#define LIS3DSH_CR4_ODR_25HZ ((uint8_t)0x04)
#define LIS3DSH_CR4_ODR_50HZ ((uint8_t)0x05)
#define LIS3DSH_CR4_ODR_100HZ ((uint8_t)0x06)
#define LIS3DSH_CR4_ODR_400HZ ((uint8_t)0x07)
#define LIS3DSH_CR4_ODR_800HZ ((uint8_t)0x08)
#define LIS3DSH_CR4_ODR_1600HZ ((uint8_t)0x09)
#define LIS3DSH_CR4_BDU_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR4_BDU_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR4_BDU_POSITION ((uint8_t)0x04)
#define LIS3DSH_CR4_Z_AXIS_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR4_Z_AXIS_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR4_Z_AXIS_POSITION ((uint8_t)0x05)
#define LIS3DSH_CR4_X_AXIS_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR4_X_AXIS_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR4_X_AXIS_POSITION ((uint8_t)0x07)
#define LIS3DSH_CR4_Y_AXIS_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR4_Y_AXIS_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR4_Y_AXIS_POSITION ((uint8_t)0x06)
#define LIS3DSH_CR5_BW_800HZ ((uint8_t)0x00)
#define LIS3DSH_CR5_BW_400HZ ((uint8_t)0x01)
#define LIS3DSH_CR5_BW_200HZ ((uint8_t)0x02)
#define LIS3DSH_CR5_BW_50HZ ((uint8_t)0x03)
#define LIS3DSH_CR5_FSCALE_2G ((uint8_t)0x00)
#define LIS3DSH_CR5_FSCALE_4G ((uint8_t)0x01)
#define LIS3DSH_CR5_FSCALE_6G ((uint8_t)0x02)
#define LIS3DSH_CR5_FSCALE_8G ((uint8_t)0x03)
#define LIS3DSH_CR5_FSCALE_16G ((uint8_t)0x04)
#define LIS3DSH_CR5_ST_DISABLE ((uint8_t)0x00)
#define LIS3DSH_CR5_ST_POSITIVE ((uint8_t)0x01)
#define LIS3DSH_CR5_ST_NEGATIVE ((uint8_t)0x02)
#define LIS3DSH_CR5_ST_NOT_ALLOWED ((uint8_t)0x03)
#define LIS3DSH_CR5_MODE_4_WIRE_INTERFACE ((uint8_t)0x00)
#define LIS3DSH_CR5_MODE_3_WIRE_INTERFACE ((uint8_t)0x01)
#define LIS3DSH_CR6_FORCE_REBOOT_DISABLE ((uint8_t)0x00)
#define LIS3DSH_CR6_FORCE_REBOOT_ENABLE ((uint8_t)0x01)
#define LIS3DSH_CR6_FIFO_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_FIFO_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_WTM_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_WTM_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_ADDINC_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_ADDINC_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_FIFO_EMPTY_TO_INT1_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_FIFO_EMPTY_TO_INT1_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_FIFO_WTM_TO_INT1_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_FIFO_WTM_TO_INT1_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_FIFO_OVERRUN_TO_INT1_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_FIFO_OVERRUN_TO_INT1_ENABLED ((uint8_t)0x01)
#define LIS3DSH_CR6_BOOT_TO_INT2_DISABLED ((uint8_t)0x00)
#define LIS3DSH_CR6_BOOT_TO_INT2_ENABLED ((uint8_t)0x01)
#define LIS3DSH_SPI SPI1
#define LIS3DSH_SPI_CLK RCC_APB2Periph_SPI1
#define LIS3DSH_SPI_SCK_PIN GPIO_Pin_5
#define LIS3DSH_SPI_SCK_GPIO_PORT GPIOA
#define LIS3DSH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOA
#define LIS3DSH_SPI_SCK_SOURCE GPIO_PinSource5
#define LIS3DSH_SPI_SCK_AF GPIO_AF_SPI1
#define LIS3DSH_SPI_MISO_PIN GPIO_Pin_6
#define LIS3DSH_SPI_MISO_GPIO_PORT GPIOA
#define LIS3DSH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOA
#define LIS3DSH_SPI_MISO_SOURCE GPIO_PinSource6
#define LIS3DSH_SPI_MISO_AF GPIO_AF_SPI1
#define LIS3DSH_SPI_MOSI_PIN GPIO_Pin_7
#define LIS3DSH_SPI_MOSI_GPIO_PORT GPIOA
#define LIS3DSH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA
#define LIS3DSH_SPI_MOSI_SOURCE GPIO_PinSource7
#define LIS3DSH_SPI_MOSI_AF GPIO_AF_SPI1
#define LIS3DSH_SPI_CS_PIN GPIO_Pin_3
#define LIS3DSH_SPI_CS_GPIO_PORT GPIOE
#define LIS3DSH_SPI_CS_GPIO_CLK RCC_AHB1Periph_GPIOE
#define LIS3DSH_SPI_INT1_PIN GPIO_Pin_0
#define LIS3DSH_SPI_INT1_GPIO_PORT GPIOE
#define LIS3DSH_SPI_INT1_GPIO_CLK RCC_AHB1Periph_GPIOE
#define LIS3DSH_SPI_INT1_EXTI_LINE EXTI_Line0
#define LIS3DSH_SPI_INT1_EXTI_PORT_SOURCE EXTI_PortSourceGPIOE
#define LIS3DSH_SPI_INT1_EXTI_PIN_SOURCE EXTI_PinSource0
#define LIS3DSH_SPI_INT1_EXTI_IRQn EXTI0_IRQn
#define LIS3DSH_SPI_INT2_PIN GPIO_Pin_1
#define LIS3DSH_SPI_INT2_GPIO_PORT GPIOE
#define LIS3DSH_SPI_INT2_GPIO_CLK RCC_AHB1Periph_GPIOE
#define LIS3DSH_SPI_INT2_EXTI_LINE EXTI_Line1
#define LIS3DSH_SPI_INT2_EXTI_PORT_SOURCE EXTI_PortSourceGPIOE
#define LIS3DSH_SPI_INT2_EXTI_PIN_SOURCE EXTI_PinSource1
#define LIS3DSH_SPI_INT2_EXTI_IRQn EXTI1_IRQn
#define LIS3DSH_CS_LOW() GPIO_ResetBits(LIS3DSH_SPI_CS_GPIO_PORT, LIS3DSH_SPI_CS_PIN)
#define LIS3DSH_CS_HIGH() GPIO_SetBits(LIS3DSH_SPI_CS_GPIO_PORT, LIS3DSH_SPI_CS_PIN)
#define LIS3DSH_FLAG_TIMEOUT ((uint32_t)0x1000)
typedef struct
{
// **** Control Register 1 ****
uint8_t SM1_Hysteresis;
uint8_t SM1_Pin;
uint8_t SM1_Enable;
// **** END OF Control Register 1 ****
// **** Control Register 2 ****
uint8_t SM2_Hysteresis;
uint8_t SM2_Pin;
uint8_t SM2_Enable;
// **** END OF Control Register 2 ****
// **** Control Register 3 ****
uint8_t CR3_Dren;
uint8_t CR3_Iea;
uint8_t CR3_Iel;
uint8_t CR3_Int2En;
uint8_t CR3_Int1En;
uint8_t CR3_Vfilt;
uint8_t CR3_Strt;
// **** END OF Control Register 3
// **** Control Register 4 ****
uint8_t CR4_Odr;
uint8_t CR4_Bdu;
uint8_t CR4_Zen;
uint8_t CR4_Yen;
uint8_t CR4_Xen;
// **** END OF Control Register 4
// **** Control Register 5 ****
uint8_t CR5_Bw;
uint8_t CR5_Fscale;
uint8_t CR5_St;
uint8_t CR5_Sim;
// **** END OF Control Register 5
// **** Control Register 6 ****
uint8_t CR6_Boot;
uint8_t CR6_FifoEn;
uint8_t CR6_WtmEn;
uint8_t CR6_AddInc;
uint8_t CR6_P1Empty;
uint8_t CR6_P1Wtm;
uint8_t CR6_P1OverRun;
uint8_t CR6_P2Boot;
// **** END OF Control Register 6
} LIS3DSH_InitTypeDef;
typedef struct
{
uint16_t x;
uint16_t y;
uint16_t z;
} accel_vector;
extern LIS3DSH_InitTypeDef deviceLIS3DSH;
extern GPIO_InitTypeDef portLIS3DSH;
extern SPI_InitTypeDef busLIS3DSH;
extern accel_vector accelData;
void LIS3DSH_Init(LIS3DSH_InitTypeDef* LIS3DSH_InitStruct);
uint32_t LIS3DSH_TIMEOUT_UserCallback(void);
void LIS3DSH_AccelInit(void);
void LIS3DSH_Read(uint8_t* pBuffer,
uint8_t ReadAddr,
uint16_t NumByteToRead);
void LIS3DSH_Write(uint8_t* pBuffer,
uint8_t WriteAddr,
uint16_t NumByteToWrite);
void LIS3DSH_FailureHandler(void);
accel_vector LIS3DSH_ReadData(void);
void LIS3DSH_SoftReset(void);
#endif
ctrl is type uin8_t and I am using IAR Embedded Workbench with C and STM32F4Discovery board. Here is a code that inits part of LIS3DSH_IniStruct:
deviceLIS3DSH.CR4_Odr=LIS3DSH_CR4_ODR_1600HZ;
deviceLIS3DSH.CR4_Bdu=LIS3DSH_CR4_BDU_ENABLED;
deviceLIS3DSH.CR4_Zen=LIS3DSH_CR4_Z_AXIS_ENABLED;
deviceLIS3DSH.CR4_Yen=LIS3DSH_CR4_Y_AXIS_ENABLED;
deviceLIS3DSH.CR4_Xen=LIS3DSH_CR4_X_AXIS_ENABLED;
and deviceLIS3DSH is declared as:
LIS3DSH_InitTypeDef deviceLIS3DSH;
The same code but with the if-statements replaced with pure bit manipulation:
// **** CONTROL REGISTER 4 SETUP ****
ctrl |= (LIS3DSH_InitStruct->CR4_Odr);
ctrl |= (LIS3DSH_InitStruct->CR4_Bdu << LIS3DSH_CR4_BDU_POSITION);
ctrl |= (LIS3DSH_InitStruct->CR4_Zen << LIS3DSH_CR4_Z_AXIS_POSITION);
ctrl |= (LIS3DSH_InitStruct->CR4_Yen << LIS3DSH_CR4_Y_AXIS_POSITION);
ctrl |= (LIS3DSH_InitStruct->CR4_Xen << LIS3DSH_CR4_X_AXIS_POSITION);
LIS3DSH_Write(&ctrl,
LIS3DSH_CTRL_REG4_ADDR,
sizeof(ctrl));
delay(1000000);
// **** END OF CONTROL REGISTER 4 SETUP ****
These are already bit manipulation.
if(LIS3DSH_InitStruct->CR4_Bdu)
This tests if the integer inside is 0 or not. The test is a logical operator, so it checks all the bits. Internally, it might be a tst assembly instruction.
ctrl|=(1<<LIS3DSH_CR4_BDU_POSITION);
Here is some actual bit manipulation. ctrl has 8 bits, and we want to make one of these a 1, even it is already is 1.
So we take 1 which is 00000001 and shift the bits left to get the 1 into the position we are concerned with. Which position is this? It is given by the macro LIS3DSH_CR4_BDU_POSITION which is defined to be a number from 0 to 7 in the header file.
So the right hand side becomes 1<<4 or 00010000 or 0x10 or 16.
The we or this number with ctrl via ctrl = ctrl | 0x10; Which has the effect of making sure the 5th bit of the ctrl integer is a 1. It is shorter to write ctrl |= (1<<4);