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);
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 .
So, whenever I need to reference certain ASCII control characters I find myself doing junk like this:
#define STX 2
#define ETX 3
Is there some C header file found in most development environments (LINUX probably) that define these constants for me so that I don't have to use magic numbers or define them all the time? Something like <stdint.h>.
I've been writing C code for 35 years and I've never come across such a header file.
The best I can do for you off the top of my head:
1. Using the Linux Documentation Project's manpage source
This file is likely to be present somewhere on your machine; the path I used is where you'll find it on a Debian/Ubuntu install. The list only includes C0 codes, but maybe that's good enough:
$ gunzip -c /usr/share/man/man7/ascii.7.gz |
> awk '$1~/0[0-3][0-7]/{printf "#define C0_%-3s %2d\n", $4, $2}'
#define C0_NUL 0
#define C0_SOH 1
#define C0_STX 2
#define C0_ETX 3
#define C0_EOT 4
#define C0_ENQ 5
#define C0_ACK 6
#define C0_BEL 7
#define C0_BS 8
#define C0_HT 9
#define C0_LF 10
#define C0_VT 11
#define C0_FF 12
#define C0_CR 13
#define C0_SO 14
#define C0_SI 15
#define C0_DLE 16
#define C0_DC1 17
#define C0_DC2 18
#define C0_DC3 19
#define C0_DC4 20
#define C0_NAK 21
#define C0_SYN 22
#define C0_ETB 23
#define C0_CAN 24
#define C0_EM 25
#define C0_SUB 26
#define C0_ESC 27
#define C0_FS 28
#define C0_GS 29
#define C0_RS 30
#define C0_US 31
2. Using the Unicode Character Database.
This includes a lot more, with lots of Unicode control characters, some of them in the astral plane, although obviously you can filter it. It also includes some extra abbreviation names. The file NamedAliases.txt can be downloaded from https://www.unicode.org/Public/14.0.0/ucd/NameAliases.txt or you can grab the entire UCD as a zipped archive at https://www.unicode.org/Public/zipped/14.0.0/
I truncated the output at 60 lines; the entire list is 353 lines.
awk -F\; '$3=="abbreviation"
{printf "#define CTL_%-8s 0x%s\n", $2, $1}' \
UCD/NameAliases.txt
#define CTL_NUL 0x0000
#define CTL_SOH 0x0001
#define CTL_STX 0x0002
#define CTL_ETX 0x0003
#define CTL_EOT 0x0004
#define CTL_ENQ 0x0005
#define CTL_ACK 0x0006
#define CTL_BEL 0x0007
#define CTL_BS 0x0008
#define CTL_HT 0x0009
#define CTL_TAB 0x0009
#define CTL_LF 0x000A
#define CTL_NL 0x000A
#define CTL_EOL 0x000A
#define CTL_VT 0x000B
#define CTL_FF 0x000C
#define CTL_CR 0x000D
#define CTL_SO 0x000E
#define CTL_SI 0x000F
#define CTL_DLE 0x0010
#define CTL_DC1 0x0011
#define CTL_DC2 0x0012
#define CTL_DC3 0x0013
#define CTL_DC4 0x0014
#define CTL_NAK 0x0015
#define CTL_SYN 0x0016
#define CTL_ETB 0x0017
#define CTL_CAN 0x0018
#define CTL_EOM 0x0019
#define CTL_SUB 0x001A
#define CTL_ESC 0x001B
#define CTL_FS 0x001C
#define CTL_GS 0x001D
#define CTL_RS 0x001E
#define CTL_US 0x001F
#define CTL_SP 0x0020
#define CTL_DEL 0x007F
#define CTL_PAD 0x0080
#define CTL_HOP 0x0081
#define CTL_BPH 0x0082
#define CTL_NBH 0x0083
#define CTL_IND 0x0084
#define CTL_NEL 0x0085
#define CTL_SSA 0x0086
#define CTL_ESA 0x0087
#define CTL_HTS 0x0088
#define CTL_HTJ 0x0089
#define CTL_VTS 0x008A
#define CTL_PLD 0x008B
#define CTL_PLU 0x008C
#define CTL_RI 0x008D
#define CTL_SS2 0x008E
#define CTL_SS3 0x008F
#define CTL_DCS 0x0090
#define CTL_PU1 0x0091
#define CTL_PU2 0x0092
#define CTL_STS 0x0093
#define CTL_CCH 0x0094
#define CTL_MW 0x0095
#define CTL_SPA 0x0096
...
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.
// 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 2 defines:
#define REG1 (BASE_ADDR + REG1_OFFSET) //address
#define REG1_MASK 0x3f
I want to generate a command through macro that would use both defines but with giving as a variable only REG1. for instance, writing down
WRITE_TO_REG(REG1)
will result in:
foo(REG1,0xa5a5a5a5,REG1_MASK)
For this I created these macros:
#define MASK_REG(REG) REG ## _MASK
#define FOO_REG(REG) foo(REG,0xa5a5a5a5,MASK_REG(REG))
but I get an error (I'm compiling in gcc): pasting ")" and "_MASK" does not give a valid preprocessing token.
I tried a few variations, including:
#define MASK_REG(REG) MASK2_REG(REG)
#define MASK2_REG(REG) IDENTITY(REG) ## _MASK
#define IDENTITY(REG) REG
or:
#define PASTE2(x,y) PASTE(x,y)
#define PASTE(x,y) x ## y
#define MASK_REG(REG) PASTE2(REG,_MASK)
None of them worked. any ideas?
Adding a complete code:
#include <stdio.h>
#define REG1_BASE_ADDR 0x100
#define REG1_OFFSET 0x5
#define REG1 (REG1_BASE_ADDR + REG1_OFFSET)
#define REG1_MASK 0x3f
#define PASTE2(x,y) PASTE(x,y)
#define PASTE(x,y) x ## y
#define MASK_REG(REG) REG ## _MASK
#define FOO_REG(REG) (REG + MASK_REG(REG))
int main() {
printf("addr: %x, mask: %x, addr+mask: %x",REG1,REG1_MASK,FOO_REG(REG1));
}
Ok, I actually think I got it.
The problem was that the macro REG1 was evaluated BEFORE pre-processsor made the paste to _MASK.
It seems I didn't need any more defines to perform the paste:
#include <stdio.h>
#define REG1_BASE_ADDR 0x100
#define REG1_OFFSET 0x5
#define REG1 (REG1_BASE_ADDR + REG1_OFFSET)
#define REG1_MASK 0x3f
#define FOO_REG(REG) (REG + REG##_MASK)
int main() {
printf("addr: %x, mask: %x, addr+mask: %x",REG1,REG1_MASK,FOO_REG(REG1));
}