How to write 8 bit data by macro in C? - c

I write TFT LCD driver for stm32 and I need write 8 bit data to LCD. I found this macro in mcufriend's library, but I'm not sure how it works and how can I edit it. Can somebody write how to write macro like this and how it works ?
Macro from mcufriend's library:
#define write_8(d) { \
GPIOA->regs->BSRR = 0x0700 << 16; \
GPIOB->regs->BSRR = 0x0438 << 16; \
GPIOC->regs->BSRR = 0x0080 << 16; \
GPIOA->regs->BSRR = (((d) & (1<<0)) << 9) \
| (((d) & (1<<2)) << 8) \
| (((d) & (1<<7)) << 1); \
GPIOB->regs->BSRR = (((d) & (1<<3)) << 0) \
| (((d) & (1<<4)) << 1) \
| (((d) & (1<<5)) >> 1) \
| (((d) & (1<<6)) << 4); \
GPIOC->regs->BSRR = (((d) & (1<<1)) << 6); \
}

That looks like STM32duino syntax:
PORT->regs->REGISTER = value
with REGISTER being BSRR, the bit set reset register. The value you assign to this sets pins 0-15 of PORT high, if the corresponding bit is set. Bits 16-31 act the same as bits 0-15 of the BRR register; if the bit is set, the corresponding pin is set low. If a bit is zero, the state of the corresponding pin is unchanged.
Lets look at each individual assignment in the macro.
GPIOA->regs->BSRR = 0x0700 << 16;
This sets pins GPIOA8, GPIOA9, and GPIOA10 low. ((1<<8) | (1<<9) | (1<<10) == 0x0700, and high 16 bits of BSRR sets the corresponding bits low.)
GPIOB->regs->BSRR = 0x0438 << 16;
This sets pins GPIOB3, GPIOB4, GPIOB5, and GPIOB10 low.
GPIOC->regs->BSRR = 0x0080 << 16;
This sets pin GPIOC7 low.
GPIOA->regs->BSRR =
(((d) & (1<<0)) << 9)
| (((d) & (1<<2)) << 8)
| (((d) & (1<<7)) << 1);
If bit 0 of d is set, then pin GPIOA9 is set high.
If bit 2 of d is set, then pin GPIOA10 is set high.
If bit 7 of d is set, then pin GPIOA8 is set high.
GPIOB->regs->BSRR =
(((d) & (1<<3)) << 0)
| (((d) & (1<<4)) << 1)
| (((d) & (1<<5)) >> 1)
| (((d) & (1<<6)) << 4);
If bit 3 of d is set, pin GPIOB3 is set high.
If bit 4 of d is set, pin GPIOB5 is set high.
If bit 5 of d is set, pin GPIOB4 is set high.
If bit 6 of d is set, pin GPIOB10 is set high.
GPIOC->regs->BSRR =
(((d) & (1<<1)) << 6);
If bit 1 of d is set, pin GPIOC7 is set high.
The first three lines set pins GPIOA8, GPIOA9, GPIOA10, GPIOB3, GPIOB4, GPIOB5, GPIOB10, and GPIOC7 low.
The rest of the lines set pins GPIOA9, GPIOC7, GPIOA10, GPIOB3, GPIOB5, GPIOB4, GPIOB10, and GPIOA8 high, if the corresponding bit in d is set.
In other words, the macro sets the pins A9,C7,A10,B3,B5,B4,B10,A8 high if the corresponding bit 0-7 in d is set, and low if clear.
I would hazard a guess that the macro is used to communicate with a peripheral (likely a display) using 8-bit parallel bus, with pin A9 corresponding to the least significant bit of each parallel byte sent, and pin A8 to the most significant bits; the other pins as listed above in between.

Related

Internal Temp Arduino

Summary: Internal temp having trouble connecting to the right channel.
Want to get right value from the channel.
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>
uint8_t ReADC()//read value ad
{
ADMUX = (1 << MUX3) | (1 << REFS0) | (1 << REFS1) | (1 << ADLAR);
//single conversion
ADCSRA |= (1 << ADEN) | (1<<ADSC) | (1 << ADPS2);
ISR(TIMER0_COMPA_vect){
ADC();
}
void SPI_MASTER(){
DDRB = (1 << PB0) | (1 << PB3) | (1 << PB5);
SPCR = (1 << CPOL) | (1 << MSTR) | (1 << SPR0) | (1 << SPI2X) | (1 << SPE);
}
}
I agree with comments — you should read DS, ADC Conversion Result and Temperature Measurement sections.
But there is a bug in measurement process (ADC usage issue) that prevent you from reading right ADC result for temperature calculation.
See:
uint8_t ReadADC()
{
ADMUX = (1 << MUX3) | (1 << REFS0) | (1 << REFS1) | (1 << ADLAR); // (1)
ADCSRA |= (1 << ADEN) | (1<<ADSC) | (1 << ADPS2) | (1 << ADPS1)
| (1 << ADPS0) | (1 << ADIE);
while( ADCSRA & (1<<ADSC) );
return ADC; // (2)
}
You (1) select ADLAR, so ADC result is shifted toward high bit of 16-bit ADCH:ADCL pair. But then (2) you read the 16-bit value and convert it into 8-bit value by throwing out high 8 bits. As a result, you get two least significant bits of ADC result in two most significant bits of returned value. So, these bits can encode 0, 64, 128, 192 only.
uint8_t SPI_transmit_data()
{
PORTB &= ~(1 << PB0);
SPDR = ADC; // (2)
while(!SPSR & (1<<SPIF));
PORTB |= (1 << PB0);
return(SPDR);
}
The same is here, the lowest 8 bits of ADC result is writed into 8-bit SPDR and higher 8 bits are thrown out.
Use ADCH instead of ADC

STM32L052 Analog-to-digital converter on registers

I went through the entire configuration of the Analog-to-digital converter [ADC]. When I worked on the registers, I made a mistake somewhere. Below are the configurations. The debugger via ST-Link after connecting 3.3 [V] to pins used in the project, during the measurement assigns them a value of 0x00 which indicates a failure. What am I doing wrong?
int main(void)
{
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
//ADC attach
RCC->IOPENR = RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
GPIOB->MODER = GPIO_MODER_MODE14_1 | GPIO_MODER_MODE15_1;
//ADC_IN8 & ADC_IN9
/* configure ADC */
ADC1->ISR &= ~ADC_ISR_EOCAL & ~ADC_ISR_AWD;
//calibration flag, WATCHDOG flag
ADC1->ISR |= ADC_ISR_ADRDY;
ADC1->CR &= ~ADC_CR_ADSTART;
//The software is allowed to write smp bit only when ADSTART=0
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
//111: 160.5 ADC clock cycles
ADC1->CFGR1 &= ~ADC_CFGR1_SCANDIR;
//Scan Direction 0: Upward scan (from CHSEL0 to CHSEL18)
ADC1->CFGR1 |= ADC_CFGR1_AWDCH_3 | ADC_CFGR1_AWDEN | ADC_CFGR1_WAIT | ADC_CFGR1_CONT | ADC_CFGR1_AUTOFF;
//AWDCH[4:0]: Analog watchdog channel selection, Continuous Mode
ADC->CCR |= ADC_CCR_LFMEN | ADC_CCR_VREFEN;
//Low Frequency Mode, V REFINT enable
ADC1->CHSELR |= ADC_CHSELR_CHSEL8 | ADC_CHSELR_CHSEL9 | ADC_CHSELR_CHSEL17;
//Channel Select 8 & 9
ADC1->IER |= ADC_IER_EOCIE | ADC_IER_EOSEQIE | ADC_IER_OVRIE | ADC_IER_EOSMPIE;
NVIC_EnableIRQ(ADC1_COMP_IRQn);
NVIC_SetPriority(ADC1_COMP_IRQn,3);
while(1)
{
ADC1->CR |= ADC_CR_ADEN;// | ADC_CR_ADSTART;
//Start the ADC conversion
while ((ADC1->ISR & ADC_ISR_ADRDY));
//Wait for stand up
while ((ADC1->ISR & ADC_ISR_EOC));
//wait for conversion flag
ADC1->CR |= ADC_CR_ADCAL;
//End of the calibration
delay(100);
uint16_t napiecie = ADC1->DR;
uint8_t hi = ((napiecie >> 8) & 0xff);
uint8_t lo = ((napiecie >> 0) & 0xff);
//DISABLE ADC
if ((ADC1->CR & ADC_CR_ADSTART) != 0){
ADC1->CR |= ADC_CR_ADSTP;
while ((ADC1->CR & ADC_CR_ADSTP) != 0);
}
ADC1->CR |= ADC_CR_ADDIS; //ADC disable command
while ((ADC1->CR & ADC_CR_ADEN) != 0);
ADC1->CR &= ~ADC_CR_ADSTART & ~ADC_CR_ADEN;
//ADC1->CR &= ~ADC_ISR_ADRDY; //Clear the ADRDY bit in ADC_ISR register by programming this bit to 1 (optional).
}
void ADC1_COMP_IRQHandler(void)
/* Interupt ADC */
{
if(ADC1->ISR & ADC_ISR_EOC){
uint16_t napiecie = ADC1->DR;
uint8_t hi = ((napiecie >> 8) & 0xff);
uint8_t lo = ((napiecie >> 0) & 0xff);
}
}
Two times you used lines like
ADC1->ISR &= ~ADC_ISR_EOCAL | ~ADC_ISR_AWD;
which looks really strange to me, as if the defines are 1 bit wide, which they most likely are, their bitwise OR is 0xFFFFFFFF (all F, no 0) and you're not changing the ISR and the CR (later in the code) at all! You need to use a bitwise AND, no?
ADC1->ISR &= ~ADC_ISR_EOCAL & ~ADC_ISR_AWD;
...
ADC1->CR &= ~ADC_CR_ADSTART & ~ADC_CR_ADEN;
Else some working code is available at https://electronics.stackexchange.com/questions/287073/get-internal-temperature-or-voltage-stm32l0/287162
https://github.com/ChristopherJD/STM32L053R8/blob/master/Intern_Project/ADC.c
and https://www.digikey.com/eewiki/pages/viewpage.action?pageId=47644832

Bit manipulation, unnecessary mask?

I'm trying to get a hold of bit manipulation in embedded c programming.
I have the following code
#define X_POS (8UL)
#define X_MASK (0x1FUL<<X_POS)
#define Y_POS (16UL)
#define Y_MASK (0x3UL<<Y_POS)
typedef struct {
uint32_t res[6];
uint32_t config[10];
} myStruct_type;
myStruct_type myStruct;
void configure (uint32_t n, uint32_t x, uint32_t y)
{
myStruct.config[n] &= ~(X_MASK | Y_MASK); // A
myStruct.config[n] |= ((x<<X_POS) & X_MASK) | ((y<<Y_POS) & Y_MASK); // B
}
int main (void)
{
configure(3, 18, 2);
while (1) { }
}
I understand that the line marked with the comment A is used for setting the bits of interest to 0, i.e. clearing the bits.
Also I understand that on the line marked with B the bits of interest are set to wanted values.
But what is the purpose of the X_MASK and Y_MASK on line B??? Aren't the values set by
(x<<X_POS) | (y<<Y_POS)
The purpose of the masking on line B is to ensure that only the bits you want set will be set. e.g. if x is 0xFFFFFFFF, the & with X_MASK will stop the bits above what you are interested in from being set.
So assuming config[0] starts out at 0, x is 0xFFFFFFFF and y is 0, without the maskingin line B, you would have
myStruct.config[0] &= ~(X_MASK | Y_MASK); // config[0] is still 0
myStruct.config[0] |= (0xFFFFFFFF << 8) | (0<< 16);
// config[0] is now 0xFFFFFF00
with the masks, the second line is
myStruct.config[0] |= ((0xFFFFFFFF<< 8) & 0x1F00) | (( 0 << 16) & 3 << 16); // B
which is
myStruct.config[0] |= 0x1F00 | 0);
If you only use (x<<X_POS) | (y<<Y_POS) you simply assign the values x and y shifted to the left.
The mask eliminates the unwanted bits. For example:
X_MASK = 0x1FUL << 8UL = 0x1F00000000 = 0b111110000...
With the logical & (AND) you set all bits to zero that are zero on your mask:
X_MASK 0b00000001111100000000.....
x<<X_POS 0b01010101010100000000.....
& ________________________
result 0b00000001010100000000.....
On a higher level you can say, that the X_MASK sets all bits of x to zero except the lowest 5 and the Y_MASK sets all bits of y to zero, except the lowest 2. Afterwards your result gets bit shifted to the left. So the mask will clear the higher bits.

Specific C shifting operations. Have a look and tell me what it is about

SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &=
~((uint32_t)0x0F) <<
(0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |=
(((uint32_t)EXTI_PortSourceGPIOx) <<
(0x04 * (EXTI_PinSourcex & (uint8_t)0x03)));
This is a piece of code from the STM32F4 board standard library. I understand every single operation but the entire code is really messy. Please accept the challenge and tell me what it is about in a more intuitive way.
And for simplicity, try to explain the situation when EXTI_PinSourcex is 0x01, and the EXTI_PortSourceGPIOx is 0x01 as well .
Any comments is appreciated, thanks in advance.
Ah, bitwise operator math.
It's easier to understand if you break it apart into pieces and "unoptimize" some of the language syntax. Let's also make the bigger variable convolutions easier to read:
SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &=
~((uint32_t)0x0F) <<
(0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
becomes:
#define cfgval_shift_2r (SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02])
cfgval_shift_2r = (cfgval_shift_2r) & ~((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
Unraveling some of the constant bitwise math (such as ~((uint32_t)0x0F)):
cfgval_shift_2r = (cfgval_shift_2r) & 0xFFF0 << (0x04 * (EXTI_PinSourcex & 0x03));
Now we have something that's a little easier to read.
EXTI_PinSourcex == 0x00:
// cfgval_shift_2r = SYSCFG->EXTICR[0], because 0 shifted any number of bits is always 0
SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0]) & 0xFFF0 << (0x04 * (0 & 0x03));
// \ == 0 /
SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0]) & 0xFFF0;
So this takes the value of SYSCFG->EXTICR[0] and simply masks the least-significant byte off and assigns it back as the value.
EXTI_PinSourcex == 0x01:
// cfgval_shift_2r = SYSCFG->EXTICR[0], because (0x01 >> 0x02) == 0
SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0]) & 0xFFF0 << (0x04 * (0x01 & 0x03));
// \ == 0x04 * 0x01 == 0x04 /
SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0]) & 0xFFF0 << 0x04;
So this takes the value of SYSCFG->EXTICR[0], masks the least-significant byte off, shifts everything to the left by 4 bits, and assigns it back as the value.
You can apply a similar breakdown to the second operation.

How to break 32 bit value and assign it to three different data types.?

I have a
#define PROT_EN_DAT 0x140
//(320 in decimal)
Its loaded into 64 bit value register(ex setup_data[39:8]=PROT_EN_DATA)
Now i want to put this value(0x140)into
uint8_t bRequest
uint16_t wValue
uint16_t wIndex
How can load the value so that i don't have to manually do it for other values again.
I think we can do with shift operators but don know how.
EDIT:Ya its related to USB. bRequest(8:15),wValue(16:31),wIndex(32:47) but setup_data is 64 bit value.I want to know how can i load proper values into the these fields.
For example say next time i am using #define PROT_EN2_REG 0x1D8.
and say setup_data[39:8]=PROT_EN2_DATA
General read form:
aField = (aRegister >> kBitFieldLSBIndex) & ((1 << kBitFieldWidth) - 1)
General write form:
mask = ((1 << kBitFieldWidth) - 1) << kBitFieldLSBIndex;
aRegister = (aRegister & ~mask) | ((aField << kBitFieldLSBIndex) & mask);
where:
aRegister is the value you read from the bit-field-packed register,
kBitFieldLSBIndex is the index of the least significant bit of the bit field, and
kBitFieldWidth is the width of the bit field, and
aField is the value of the bit field
These are generalized, and some operations (such as bit-masking) may be unnecessary in your case. Replace the 1 with 1L if the register is larger than 32 bits.
EDIT: In your example case (setup_data[39:8]=PROT_EN_DATA):
Read:
aField = (setup_data >> 8) & ((1L << 32) - 1L)
Write:
#define PROT_EN_MASK = (((1L << 32) - 1L) << 8) // 0x0000000FFFFFFFF0
setup_data = (setup_data & ~PROT_EN_MASK) | ((PROT_EN_DATA << 8) & PROT_EN_MASK);

Resources