Closed nopnop2002 closed 4 years ago
stm32 have got more pins on one port than atmega
Where this API is described? This is not an official one? You can use LL or direct access register to do this.
What is LL??
Actual Ardino Code:
void setup() {
DDRD = DDRD | B11111111; // output pins D0-D7
PORTD = B10101000; // Digital pins D7, D5, D3 set to HIGH
}
void loop() {
// put your main code here, to run repeatedly:
}
This allows for fast parallel IO.
But Arduino_Core_STM32 is not support this.
It is possible to operate multiple GPIOs by manipulating the registers directly, but it is not general purpose.
STM32F103: GPIOx_CRL,GPIOx_CRH,GPIOx_ODR
STM32F303: GPIOx_MODER,GPIOx_OTYPER,GPIOx_ODR
I'm happy if Arduino_Core_STM32 supports this (or similar feature)
What is LL??
This is:
The Low Layer APIs (LL) offering a fast light-weight expert-oriented layer which is closer to the hardware than the HAL. The LL APIs are available only for a set of peripherals.
About:
Actual Ardino Code: ...
In fact you want this: https://www.arduino.cc/en/Reference/PortManipulation
This is purely related to some AVR.
The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:
B (digital pin 8 to 13) C (analog input pins) D (digital pins 0 to 7)
STM32 has several port A up to K and 16 pins for each and this not inline with the pin numbering.
You can use the CMSIS definition to achieve this easily. Several libraries already do this or using those functions: https://github.com/stm32duino/Arduino_Core_STM32/blob/a9fdc93fc8b2d5739f0d2100d81a83789dd0bbd0/cores/arduino/pins_arduino.h#L293-L318
Or you can use the LL GPIO by including "stm32yyxx_ll_gpio.h" and using all LLGPIO* functions. Refers to description of STM32xx HAL and LL drivers, example for F4: https://www.st.com/resource/en/user_manual/dm00105879-description-of-stm32f4-hal-and-ll-drivers-stmicroelectronics.pdf
Note that Teensy implement an AVR emulation: https://github.com/PaulStoffregen/cores/blob/f9a9f867c565b0740cd9a36c10bc2e6a6638fa00/teensy4/avr_emulation.h
It can be done like this but this is confusing because for PORTD this would not means GPIO PORT D but all digital pins 0 to 7 which can be on different GPIO port...
LL is not that scary for GPIO lets imagine we need to set pins on PD0/PD1/PD2
__HAL_RCC_GPIOD_CLK_ENABLE(); // enable GPIO port D clock
/* set pin mode */
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_1, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_2, LL_GPIO_MODE_OUTPUT);
/* output type, use LL_GPIO_OUTPUT_OPENDRAIN for open drain active low pins */
LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2, LL_GPIO_OUTPUT_PUSHPULL);
/* no pullup or pulldown for output pins */
LL_GPIO_SetPinPull(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2, LL_GPIO_PULL_NO);
/* set gpio speed */
LL_GPIO_SetPinSpeed(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2, LL_GPIO_SPEED_FREQ_HIGH);
/* and finally */
LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2);
/* or */
LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2);
/* or */
LL_GPIO_TogglePin(GPIOD, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2);
@stas2z It was LL_GPIO_TogglePin instead of LL_GPIO_ToggleOutputPin. This code work fine with STM32F103/F303/F401/F405.
void setup() {
pinMode(PA0, OUTPUT);
pinMode(PA1, OUTPUT);
pinMode(PA2, OUTPUT);
pinMode(PA3, OUTPUT);
pinMode(PA4, OUTPUT);
LL_GPIO_WriteOutputPort(GPIOA, 0);
}
void loop(){
LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2 | LL_GPIO_PIN_3 | LL_GPIO_PIN_4);
delay(1000);
}
@fpistm
I found the following document, but this document was not published by STM.
For many people, STM need to provide API documentation or sample code.
You may publish it here.
https://github.com/stm32duino/wiki/wiki
https://github.com/stm32duino/wiki/wiki/Examples
Thank you for your help.
I tried the effect of LL_GPIO_WriteOutputPort() on some board.
digitalWrite Code:
uint32_t Pins[] = {PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7};
void write8(uint8_t bytes) {
for(uint8_t bits=0;bits<8;bits++) {
uint8_t mask = 1<<bits;
#if 0
Serial.print("mask=");
Serial.print(mask,HEX);
Serial.print(" ");
Serial.println((bytes & mask), HEX);
#endif
if ( (bytes & mask) != 0 ) {
digitalWrite(Pins[bits], HIGH);
} else {
digitalWrite(Pins[bits], LOW);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(PA0, OUTPUT);
pinMode(PA1, OUTPUT);
pinMode(PA2, OUTPUT);
pinMode(PA3, OUTPUT);
pinMode(PA4, OUTPUT);
pinMode(PA5, OUTPUT);
pinMode(PA6, OUTPUT);
pinMode(PA7, OUTPUT);
write8(0x0);
}
void loop(){
uint8_t bytes = 0;
uint32_t smill = millis();
for(uint32_t i=0;i<100000;i++) {
write8(bytes);
bytes++;
//delay(100);
}
uint32_t emill = millis();
Serial.print("Elasped=");
Serial.println(emill - smill);
}
LL_GPIO_WriteOutputPort Code:
uint32_t Pins[] = {LL_GPIO_PIN_0, LL_GPIO_PIN_1, LL_GPIO_PIN_2, LL_GPIO_PIN_3, LL_GPIO_PIN_4, LL_GPIO_PIN_5, LL_GPIO_PIN_6, LL_GPIO_PIN_7};
void write8(uint8_t bytes) {
uint32_t PinMask = 0;
//PinMask = 0;
for(uint8_t bits=0;bits<8;bits++) {
uint8_t mask = 1<<bits;
#if 0
Serial.print("mask=");
Serial.print(mask,HEX);
Serial.print(" ");
Serial.println((bytes & mask), HEX);
#endif
if ( (bytes & mask) != 0 ) PinMask = PinMask + Pins[bits];
}
#if 0
Serial.print("bytes=");
Serial.print(bytes,HEX);
Serial.print(" PinMask=");
Serial.println(PinMask,HEX);
#endif
LL_GPIO_WriteOutputPort(GPIOA, PinMask);
}
void setup() {
Serial.begin(115200);
pinMode(PA0, OUTPUT);
pinMode(PA1, OUTPUT);
pinMode(PA2, OUTPUT);
pinMode(PA3, OUTPUT);
pinMode(PA4, OUTPUT);
pinMode(PA5, OUTPUT);
pinMode(PA6, OUTPUT);
pinMode(PA7, OUTPUT);
write8(0x0);
}
void loop(){
uint8_t bytes = 0;
uint32_t smill = millis();
for(uint32_t i=0;i<100000;i++) {
write8(bytes);
bytes++;
//delay(100);
}
uint32_t emill = millis();
Serial.print("Elasped=");
Serial.println(emill - smill);
}
digitalWrite | LL_GPIO_WriteOutputPort | Faster | |
---|---|---|---|
STM32F103 | 924 | 252 | x3.6 |
STM32F303 | 855 | 218 | x3.9 |
STM32F401 | 399 | 129 | x3.1 |
STM32F405 | 205 | 67 | x3.1 |
It is about three times faster. I'm very glad if i gets more fast.
reference: Output from D2 to D9 using ATMega328
digitalWrite | PortManipulation | |
---|---|---|
ATmega328 | 5204 | 264 |
But I am satisfied because it is faster than ATmega328
Thank you for your help.
Oh, sorry for toggle mistake Im not sure you can make it faster than with LL, cuz LL are mostly wrappers around registers The only way to spend less time on it, to write your port with dma probably
@stas2z
Thanks for very useful information. I was able to get very useful information in 24 hours. I am very happy with this result.
@fpistm
Such useful information should be widely publicized.
@fpistm
I found the following document, but this document was not published by STM.
For many people, STM need to provide API documentation or sample code.
it's provided, for example for F4 but im sure similar docs exist for other series https://www.st.com/resource/en/user_manual/dm00105879-description-of-stm32f4-hal-and-ll-drivers-stmicroelectronics.pdf
I found your post easier to understand than this document. https://www.st.com/resource/en/user_manual/dm00105879-description-of-stm32f4-hal-and-ll-drivers-stmicroelectronics.pdf
Yes, all use manual are available on st.com: https://www.st.com/content/st_com/en/search.html#q=Descriptions%20hal%20and%20ll-t=resources-page=1
Do not hesitate to provide an example in STM32Exampes library or in the forum.
Note that all HAL and LL ca be used for for all purposes.
@stas2z @fpistm
I close this isuues.
Japan is the season for cherry blossoms. Thank you for your help.
Feature request:
Arduino for ATmega has an API for operating multiple GPIOs collectively on a per port basis.
By using this, for example, TFT of 8-bit parallel I/F can be handled at high speed.
Arduino_Core_STM32 does not have such an API.
We hope that such an API can be used in the future.
My Image:
to
I look forward to your consideration.