STM32F103を使ってみる

レジスター操作による高速Lチカ


こちらのIL9341 8ビットパラレルTFT用のライブラリのソースでは、GPIO出力をレジスター操作で行っています。
レジスター操作によるLチカのサンプルを以下に示します。
PA0からPA7をレジスター操作でON/OFFしています。
#include "Arduino.h"
#include <avr/pgmspace.h>

#define PA0_MASK   digitalPinToBitMask(PA0)
#define PA1_MASK   digitalPinToBitMask(PA1)
#define PA2_MASK   digitalPinToBitMask(PA2)
#define PA3_MASK   digitalPinToBitMask(PA3)
#define PA4_MASK   digitalPinToBitMask(PA4)
#define PA5_MASK   digitalPinToBitMask(PA5)
#define PA6_MASK   digitalPinToBitMask(PA6)
#define PA7_MASK   digitalPinToBitMask(PA7)

#define PA0_LOW    GPIOA->regs->BRR  = PA0_MASK
#define PA0_HIGH   GPIOA->regs->BSRR = PA0_MASK
#define PA1_LOW    GPIOA->regs->BRR  = PA1_MASK
#define PA1_HIGH   GPIOA->regs->BSRR = PA1_MASK
#define PA2_LOW    GPIOA->regs->BRR  = PA2_MASK
#define PA2_HIGH   GPIOA->regs->BSRR = PA2_MASK
#define PA3_LOW    GPIOA->regs->BRR  = PA3_MASK
#define PA3_HIGH   GPIOA->regs->BSRR = PA3_MASK
#define PA4_LOW    GPIOA->regs->BRR  = PA4_MASK
#define PA4_HIGH   GPIOA->regs->BSRR = PA4_MASK
#define PA5_LOW    GPIOA->regs->BRR  = PA5_MASK
#define PA5_HIGH   GPIOA->regs->BSRR = PA5_MASK
#define PA6_LOW    GPIOA->regs->BRR  = PA6_MASK
#define PA6_HIGH   GPIOA->regs->BSRR = PA6_MASK
#define PA7_LOW    GPIOA->regs->BRR  = PA7_MASK
#define PA7_HIGH   GPIOA->regs->BSRR = PA7_MASK

#define PA_SET(c)  GPIOA->regs->BSRR = ((~c)<<16) | (c)  //Set pins to the 8 bit number

#define DEBUG 0

void setup() {

  GPIOA->regs->CRL = 0x33333333;
  GPIOA->regs->CRH = 0x33333333;
  GPIOB->regs->CRL = 0x33333333;
  GPIOB->regs->CRH = 0x33333333;

  PA0_LOW;
  PA1_LOW;
  PA2_LOW;
  PA3_LOW;
  PA4_LOW;
  PA5_LOW;
  PA6_LOW;
  PA7_LOW;

  PA0_HIGH;
  delay(200);
  PA1_HIGH;
  delay(200);
  PA2_HIGH;
  delay(200);
  PA3_HIGH;
  delay(200);
  PA4_HIGH;
  delay(200);
  PA5_HIGH;
  delay(200);
  PA6_HIGH;
  delay(200);
  PA7_HIGH;
  delay(200);

  uint8_t c;
  c=0x00;
  PA_SET(c);
  for(int i=0;i<8;i++) {
    c = (c << 1) + 1;
//    Serial.println(c,HEX);
    PA_SET(c);
    delay(200);
  }
  c=0x00;
  PA_SET(c);

  Serial.print("test1 ");
  Serial.println(test1());

  Serial.print("test2 ");
  Serial.println(test2());

  Serial.print("test3 ");
  Serial.println(test3());

}

void loop() {
  // put your main code here, to run repeatedly:

}

unsigned long test1() {
  unsigned long start = micros();
  int loop = 1000;
  if (DEBUG) loop = 1;
  for (int l=0;l<loop;l++) {
    PA0_HIGH;
    if (DEBUG) delay(200);
    PA1_HIGH;
    if (DEBUG) delay(200);
    PA2_HIGH;
    if (DEBUG) delay(200);
    PA3_HIGH;
    if (DEBUG) delay(200);
    PA4_HIGH;
    if (DEBUG) delay(200);
    PA5_HIGH;
    if (DEBUG) delay(200);
    PA6_HIGH;
    if (DEBUG) delay(200);
    PA7_HIGH;
    if (DEBUG) delay(200);
    PA0_LOW;
    if (DEBUG) delay(200);
    PA1_LOW;
    if (DEBUG) delay(200);
    PA2_LOW;
    if (DEBUG) delay(200);
    PA3_LOW;
    if (DEBUG) delay(200);
    PA4_LOW;
    if (DEBUG) delay(200);
    PA5_LOW;
    if (DEBUG) delay(200);
    PA6_LOW;
    if (DEBUG) delay(200);
    PA7_LOW;
    if (DEBUG) delay(200);
  }
  return micros() - start;
}


unsigned long test2() {
  unsigned long start = micros();
  int loop = 1000;
  if (DEBUG) loop = 1;
  for (int l=0;l<loop;l++) {
    digitalWrite(PA0,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA1,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA2,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA3,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA4,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA5,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA6,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA7,HIGH);
    if (DEBUG) delay(200);
    digitalWrite(PA0,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA1,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA2,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA3,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA4,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA5,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA6,LOW);
    if (DEBUG) delay(200);
    digitalWrite(PA7,LOW);
    if (DEBUG) delay(200);
  }
  return micros() - start;
}


unsigned long test3() {
  unsigned long start = micros();
  int loop = 1000;
  uint8_t c = 0x00;

  if (DEBUG) loop = 1;
  for(int l=0;l<loop;l++) {
    for(int i=0;i<8;i++) {
      c = (c << 1) + 1;
      if (DEBUG) Serial.println("c=" + String(c,HEX));
      PA_SET(c);
      if (DEBUG) delay(200);
    }
    uint8_t mask = 0xff;
    for(int i=0;i<8;i++) {
      mask = mask << 1;
      c = c & mask;
      if (DEBUG) Serial.println("c=" + String(c,HEX));
      PA_SET(c);
      if (DEBUG) delay(200);
    }
  }
  return micros() - start;
}

test1() test2() test3()は全て同じ内容で、PA0→PA1→PA2の順番でHIGHにし、同じ順番でLOWにします。
DEBUGを1にすると1回だけdelay付きで動きます。
1000回のパフォーマンスは以下のようになります。
時間の単位はmicrosecondsです。
レジスター操作によるLチカ 2165
digitalWrite()によるLチカ 10120
レジスター操作によるパラレル出力 2828

レジスター操作にすると4倍程度早くLチカできます。
レジスター操作のやり方が分かったので、次回は自作の8ビットパラレルTFTライブラリを紹介します。

続く...