cancel
Showing results for 
Search instead for 
Did you mean: 

What is better "Direct Resistor access or using Library"

sanju
Senior

Hi all,

from last 8 yrs i am writing programs for microcontrollers (mostly project on microchip, st) 8 bit/ 32 bit.

i always write programs by writing directly to the registers. i never used any library like SPL, HAL, LL doesn't matter how long the code is i always directly write to registers .

what is better way writing directly to registers or using any library by future prospective of my carrer.

i wrote something like this.

////////////////////////////////////////////////////////////////////

#include "stm32f0xx.h"

#include "stm32f030x8.h"

void GPIO_Init(void);

void ADC_Init(void);

void TIM3_Init(void);

void delay(void);

unsigned int i=0,j=0,count = 0, data[10],avg = 0,diff=0,run_curr= 0,last_curr= 0,stability=0,FB=0,out_curr=0,aux_out_curr=0,last_out_curr=0,duty_cycle=0;

unsigned long input=0,k=0;

int read=5;

int main()

{

/****start PLL setting for system clock at 48Mhz using 8Mhz HSI****/

RCC->CFGR |= ((1<<19)|(1<<21)); // PLL Multification factor = 12

RCC->CFGR |= (1<<1); // PLL selected as system clock

RCC->CR |= (1<<24); // Enable / ON PLL

while((RCC->CR & (1<<25)) == 0); // Wait until PLL gets Ready

/****PLL settigs end here****/

GPIO_Init();

TIM3_Init();

ADC_Init();

while(1)

{

/****** Input current sense routine*******/

//data = 0;

ADC1->CHSELR = (1<<0);

for(i = 0; i <=9; i++)

{

input = 0;

for(j = 1; j <=100; j++)

{

if ((ADC1->CR & (1<<2)) == 0)

{

ADC1->CR |= (1<<2);

}

while((ADC1->ISR & (1<<2)) == 0);

input += ADC1->DR;

}

data[i] = input/100;

//for(k=1;k<100000;k++);

}

/****** Input current Sense routine ends here******/

if((data[9] >=3315)) // 11.1V - 11.6V

{

if(data[9]>=data[0])

{

diff=data[9]-data[0];

}

else

{

diff=data[0]-data[9];

}

if(diff < 2)

{

run_curr = data[9];

ADC1->CHSELR = (1<<7);

input = 0;

for(j = 1; j <=100; j++)

{

if ((ADC1->CR & (1<<2)) == 0)

{

ADC1->CR |= (1<<2);

}

while((ADC1->ISR & (1<<2)) == 0);

input += ADC1->DR;

}

out_curr = input/100;

}

else

{

}

GPIOA->ODR &= ~(1<<5); //LED INDICATION OFF

GPIOA->ODR |= (1<<4); // Mosfet 1 ON

GPIOB->ODR &= ~(1<<0); // Mosfet 2 Off

TIM3->CCR1 = 1800; // duty cylce = 25%

/*ADC1->CHSELR = (1<<1);

input = 0;

for(j = 1; j <=100; j++)

{

if ((ADC1->CR & (1<<2)) == 0)

{

ADC1->CR |= (1<<2);

}

while((ADC1->ISR & (1<<2)) == 0);

input += ADC1->DR;

}

FB = input/100;

if(FB<=(run_curr))

{

duty_cycle++;

if(duty_cycle>360)

{

duty_cycle = 360;

}

TIM3->CCR1 = duty_cycle;

}

else if(FB>(run_curr))

{

duty_cycle--;

TIM3->CCR1 = duty_cycle;

}*/

}

else

{

//stability = 0;

last_out_curr = out_curr;

//last_curr = run_curr;

GPIOA->ODR |= (1<<5); //LED INDICATION ON

GPIOA->ODR &= ~(1<<4); // Mosfet 1 Off

GPIOB->ODR |= (1<<0); // Mosfet 2 ON

//TIM3->CCR1 = 200; // duty cylce = 25%

ADC1->CHSELR = (1<<7);

input = 0;

for(j = 1; j <=100; j++)

{

if ((ADC1->CR & (1<<2)) == 0)

{

ADC1->CR |= (1<<2);

}

while((ADC1->ISR & (1<<2)) == 0);

input += ADC1->DR;

}

aux_out_curr = input/100;

if(aux_out_curr==last_out_curr)

{

}

if(aux_out_curr<last_out_curr)

{

duty_cycle++;

if(duty_cycle>1870)

{

duty_cycle = 1870;

}

TIM3->CCR1 = duty_cycle;

}

else if(aux_out_curr>last_out_curr)

{

duty_cycle--;

TIM3->CCR1 = duty_cycle;

}

}

}

}

void GPIO_Init()

{

RCC->AHBENR |= (1<<17); // Enable clock for GPIOA

RCC->AHBENR |= (1<<18); // Enable clock for GPIOB

GPIOA->MODER |= (1<<10);       // PA5 as general purpose output mode

GPIOA->OTYPER &= ~(1<<5);      // PA5 as output push pull

GPIOA->OSPEEDR |= ((1<<10)|(1<<11)); // PA5 at high speed

GPIOA->PUPDR &= ~((1<<10)|(1<<11)); // PA5 as no pull-up, pull-down

GPIOA->ODR &= ~(1<<5); // PA5 at low ouput level

GPIOA->MODER |= (1<<8);       // PA4 as general purpose output mode

GPIOA->OTYPER &= ~(1<<4);      // PA4 as output push pull

GPIOA->OSPEEDR |= ((1<<8)|(1<<9)); // PA4 at high speed

GPIOA->PUPDR &= ~((1<<8)|(1<<9)); // PA4 as no pull-up, pull-down

GPIOA->ODR &= ~(1<<4); // PA4 at low ouput level

GPIOB->MODER |= (1<<0);       // PB0 as general purpose output mode

GPIOB->OTYPER &= ~(1<<0);      // PB0 as output push pull

GPIOB->OSPEEDR |= ((1<<0)|(1<<1)); // PB0 at high speed

GPIOB->PUPDR &= ~((1<<0)|(1<<1)); // PB0 as no pull-up, pull-down

GPIOB->ODR |= (1<<0); // PB0 at high ouput level

GPIOA->MODER &= ~((1<<0)|(1<<1)); // PA0 as input mode

GPIOA->PUPDR &= ~((1<<0)|(1<<1)); // PA0 as no pull-up, pull-down

GPIOA->MODER &= ~((1<<2)|(1<<3)); // PA1 as input mode

GPIOA->PUPDR &= ~((1<<2)|(1<<3)); // PA1 as no pull-up, pull-down

GPIOA->MODER &= ~((1<<14)|(1<<15)); // PA7 as input mode

GPIOA->PUPDR &= ~((1<<14)|(1<<15)); // PA7 as no pull-up, pull-down

GPIOA->MODER |= (1<<13); // PA6 in alternate function mode

GPIOA->OTYPER &= ~(1<<6); // PA6 as output push pull

GPIOA->OSPEEDR |= ((1<<12)|(1<<13)); // PA6 at high speed

GPIOA->PUPDR &= ~((1<<12)|(1<<13)); // PA6 no pull-up, no pull-down

GPIOA->AFR[0] |= (1<<24); // PA6 as TIM3_CH1 alternate function

}

void ADC_Init()

{

RCC->APB2ENR |= (1<<9); // Enable clock for ADC

ADC1->CFGR2 |= (1<<30); // ADC clock = PCLK/2

ADC1->CFGR1 &= ~((1<<3)|(1<<4)); // 12 bit resolution

ADC1->CR = 1; // Enable ADC

while((ADC1->ISR & 1) ==0); // Wait for ADC Ready

ADC1->CFGR1 &= ~(1<<13); // Single conversion mode

ADC1->CFGR1 &= ~((1<<10)|(1<<11)); // Software tiggerd

ADC1->CFGR1 &= ~(1<<5); // Converted data RIGHT alignment

ADC1->CFGR1 &= ~(1<<2); // Upward sequence of conversion CH0 to CH17

ADC1->SMPR |= ((1<<0)|(1<<1)); // sampling time = 28.5 ADC clock

//ADC1->CHSELR |= ((1<<0)|(1<<1)); // CH0,CH1 is selected for conversion

}

void TIM3_Init()

{

RCC->APB1ENR |= (1<<1); // Enable clock for TIM3

// Configuration of TIM3_CH1 as PWM output Mode1 with 15% duty cycle @ 40KHz

// TIM3 clock = 8000000Hz

// PSC = 0 i.e. TIM3 counting clock will be same a timer clock 8000000Hz

// ARR = 399 i.e. pwm output freq. = (Timer counter clock / (ARR+1)) = (8000000 / (399+1)) = 20000Hz

 // CCR1 = 100 i.e. duty cycle = (CCR1 / (ARR+1)) = (100 / (399+1)) = 25%

TIM3->PSC = 0;

TIM3->ARR = 2399;

TIM3->CCMR1 |= ((1<<5)|(1<<6)); // TIM3_CH1 as PWM mode-1 

TIM3->CCR1 = 0; // initaillay duty cylce = 0

TIM3->CCER = 1; // TIM3_CH1 is Active, active high 

TIM3->CR1 = 1; // TIM3 Counter enable

}

void delay()

{

for(k=1;k<2500000;k++);

}

/////////////////////////////////////////////////////////////

this code is small but for lengthy code i have same habit.

i know one advantage it makes my hex file less size.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

> what is better way writing directly to registers or using any library by future prospective of my carrer.

It's going to vary depending on what you want to do.

HAL is fine, there are an increasing number of examples, it's supported by ST.

Direct register access is future-proof, as long as the chips exist. Also a fine option.

LL is mostly a renamed direct register access. I do not recommend it ever.

One problem with direct register is it's hard to read. Compare

RCC->AHBENR |= (1<<17); // Enable clock for GPIOA

and

__HAL_RCC_GPIOA_CLK_ENABLE();

One of them relies on comments to explain what it's doing. One of them relies on the library to be correct. If I'm inheriting a project from a random developer, I'll trust the library way more than the comments. Suppose the pin is changed from GPIOA to GPIOB and someone changes the 1<<17 value, but not the comment. You're probably going to spend a bit tracking down that bug.

Another example:

TIM3->CR1 = 1; // TIM3 Counter enable

This is hard to read. Again, you're relying on the comments. There are standard CMSIS headers that have all the bits defined. Do this instead:

TIM3->CR1 |= TIM_CR1_CEN;

It makes the code way more readable.

> i know one advantage it makes my hex file less size.

While true, with the larger flash memory chips (1-2MB), this isn't typically a limiting factor.

Ultimately, for the "future prospective of my career," the most beneficial thing would be to be flexible and understand how to work in both environments. Realize a large part of programming is working with other people's code and not your own. Understand that things change and the best thing today is unlikely be the best thing 20 years from now. The longevity of C and C++ is an anomaly.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

6 REPLIES 6
TDK
Guru

> what is better way writing directly to registers or using any library by future prospective of my carrer.

It's going to vary depending on what you want to do.

HAL is fine, there are an increasing number of examples, it's supported by ST.

Direct register access is future-proof, as long as the chips exist. Also a fine option.

LL is mostly a renamed direct register access. I do not recommend it ever.

One problem with direct register is it's hard to read. Compare

RCC->AHBENR |= (1<<17); // Enable clock for GPIOA

and

__HAL_RCC_GPIOA_CLK_ENABLE();

One of them relies on comments to explain what it's doing. One of them relies on the library to be correct. If I'm inheriting a project from a random developer, I'll trust the library way more than the comments. Suppose the pin is changed from GPIOA to GPIOB and someone changes the 1<<17 value, but not the comment. You're probably going to spend a bit tracking down that bug.

Another example:

TIM3->CR1 = 1; // TIM3 Counter enable

This is hard to read. Again, you're relying on the comments. There are standard CMSIS headers that have all the bits defined. Do this instead:

TIM3->CR1 |= TIM_CR1_CEN;

It makes the code way more readable.

> i know one advantage it makes my hex file less size.

While true, with the larger flash memory chips (1-2MB), this isn't typically a limiting factor.

Ultimately, for the "future prospective of my career," the most beneficial thing would be to be flexible and understand how to work in both environments. Realize a large part of programming is working with other people's code and not your own. Understand that things change and the best thing today is unlikely be the best thing 20 years from now. The longevity of C and C++ is an anomaly.

If you feel a post has answered your question, please click "Accept as Solution".

Thank you for your reply.

Mentioning each point/part of question with good explanation, such a very nice reply​

Thanks once again​

prain
Senior III

library option is good. I recommend using libraries unless:

1- you need the firmware to run in fastest speed possible

2- you need to use the maximum functionality of hardware. some special functionalities are not covered by libraries because they are rarely used.

you can choose the proper way based on your project requirements.​

@prain​ 

yes you are right.

please clear one thing also to use HAL library in keil is it compulsory to use CubeMX. because when i create a project in keil and select device > startup or device > STM32CubeHAL it says configuration through cubemx is required. as shown in image

0693W000003Otn3QAC.png

you don't need to make a new project in keil from scratch. cubemx generates all thing you need (source files, keil project file and ... ). It is the fastest way you can generate new project. Take a look on cubemx page in st website. there are very good documents to start.

@prain​ 

Yes I have done 2 projects by directly creating project from cube mx

Configuration of each pin, clock in cubemx and generating keil project with all configuration code written by cubemx.

That's very easy.​