2018年9月27日木曜日

割り込みでSTM32F103をスリープから起こす

前回、「STM32F103C8T6をスリープ状態にする」について書きました。

今回、一定の時間から起きる状態に加えて、外部割込みからも起きるようにしたくて、色々試しました。
やはりstm32sleepライブラリーはうまくできず、前回のtomtorさんのコードをもとにテストプログラムをつくりました。
外部割込みを使うため、attachInterruptという関数を使います。
attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
BOARD_BUTTON_PINにスイッチをつけ、そのスイッチに変化があれば割込みが発生します。
そして、起きたら、何を実行するかは新たにactionという関数を設けました。
tomtorさんのAlarmFunctionという関数は、スリープから起きた際、クロックを再設定する操作があります。そのままactionの中に使います。
void action()
{
  AlarmFunction ();
  if (state == LOW) state = HIGH;
  else state = LOW;
}
ここはただLEDの点灯状態を反対にするだけ。

全部のコードは以下の通りです。

#include <RTClock.h>
#include <libmaple/pwr.h>
#include <libmaple/scb.h>

#define LED  PC13
#define BOARD_BUTTON_PIN PB0

// Define the Base address of the RTC registers (battery backed up CMOS Ram), so we can use them for config of touch screen or whatever.
// See http://stm32duino.com/viewtopic.php?f=15&t=132&hilit=rtc&start=40 for a more details about the RTC NVRam
// 10x 16 bit registers are available on the STM32F103CXXX more on the higher density device.
#define BKP_REG_BASE   ((uint32_t *)(0x40006C00 + 0x04))

// Setup RTClock for sleep
RTClock rt(RTCSEL_LSI, 39); // 1 milli second alarm
long int alarmDelay = 10;

void storeBR(int i, uint32_t v) {
  BKP_REG_BASE[2*i]= (v << 16);
  BKP_REG_BASE[2*i+1]= (v & 0xFFFF);
}

uint32_t readBR(int i) {
  return ((BKP_REG_BASE[2*i] & 0xFFFF) >> 16) | (BKP_REG_BASE[2*i+1] & 0xFFFF);
}

void sleepMode(bool deepSleepFlag) { 
  // Clear PDDS and LPDS bits
  PWR_BASE->CR &= PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF;

  // Set PDDS and LPDS bits for standby mode, and set Clear WUF flag (required per datasheet):
  PWR_BASE->CR |= PWR_CR_CWUF;
  // Enable wakeup pin bit.
  PWR_BASE->CR |=  PWR_CSR_EWUP;
  
  SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;

  // System Control Register Bits. See...
  // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Cihhjgdh.html
  if (deepSleepFlag) {
    // Set Power down deepsleep bit.
    PWR_BASE->CR |= PWR_CR_PDDS;
    // Unset Low-power deepsleep.
    PWR_BASE->CR &= ~PWR_CR_LPDS;
  } else {
    adc_disable(ADC1);
    adc_disable(ADC2);
#if STM32_HAVE_DAC
    dac_disable_channel(DAC, 1);
    dac_disable_channel(DAC, 2);
#endif
    //  Unset Power down deepsleep bit.
    PWR_BASE->CR &= ~PWR_CR_PDDS;
    // set Low-power deepsleep.
    PWR_BASE->CR |= PWR_CR_LPDS;
  }

  // Now go into stop mode, wake up on interrupt
  asm("    wfi");

  // Clear SLEEPDEEP bit so we can use SLEEP mode
  SCB_BASE->SCR &= ~SCB_SCR_SLEEPDEEP;
}

uint32 sleepTime;

void AlarmFunction () {
  // We always wake up with the 8Mhz HSI clock!
  // So adjust the clock if needed...

#if F_CPU == 8000000UL
  // nothing to do, using about 12 mA
#elif F_CPU == 16000000UL
  rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_2);
#elif F_CPU == 48000000UL
  rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_6);
#elif F_CPU == 72000000UL
  rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_9);   // 72MHz  => 48 mA  -- datasheet value           => between 40 and 41mA
#else
#error "Unknown F_CPU!?"
#endif
  
  extern volatile uint32 systick_uptime_millis;
  systick_uptime_millis+= sleepTime;
}

void mdelay(int n, bool mode= false) {
  sleepTime= n;
  time_t nextAlarm = (rt.getTime() + n); // Calculate from time now.
  rt.createAlarm(&AlarmFunction, nextAlarm);
  sleepMode(mode);
}


#define   RCC_CFGR_HPRE_DIV1   0x00000000U
#define   RCC_CFGR_HPRE_DIV2   0x00000080U
#define   RCC_CFGR_HPRE_DIV4   0x00000090U
#define   RCC_CFGR_HPRE_DIV8   0x000000A0U
#define   RCC_CFGR_HPRE_DIV16   0x000000B0U
#define   RCC_CFGR_HPRE_DIV64   0x000000C0U
#define   RCC_CFGR_HPRE_DIV128   0x000000D0U
#define   RCC_CFGR_HPRE_DIV256   0x000000E0U
#define   RCC_CFGR_HPRE_DIV512   0x000000F0U


void msleep(uint32_t ms) {
  uint32_t start= rt.getTime();
  
  while (rt.getTime() - start < ms) {
    asm("    wfi");
  }
}

int state = LOW;

void setup() {
  pinMode(LED,OUTPUT);
  pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP);
}

void loop() { 
  digitalWrite(LED,state);
  delay(60);  
  attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
  mdelay(alarmDelay * 1000);
}  

void action()
{
  AlarmFunction ();
  if (state == LOW) state = HIGH;
  else state = LOW;
}


2018年9月24日月曜日

バーチャルアシスタントを使いませんか?

外国人向けのバーチャルアシスタントサービスを発見。
ま、私は自分でできるので、必要ないと思いますが、あまり日本語のできない知り合いに紹介できるではないかと思います。
例えば、先日、元同僚(今、ドローン会社を経営)が最近、日本市場に進出しようとしています。よく日本にくるので、このサービスがあれば便利でしょう。

Virtual Assist Japan

フリートライアルもあります。
一時間だけですけど。

今度、とりあえず使ってみようかな?😅

2018年9月23日日曜日

激辛ゲット

これ、知っていますか?
ハバネロという唐辛子の仲間です。
とてもとても辛いです。
醤油につけるため、輪切りしただけで、指先がピリピリ。
切った後、目を触ったら大変!

ハバネロと出会ったのが、書道の先生のところに行った時です。
ピーマンと思って植えた先生が、「これ、とても辛いよ」と言われました。
辛いものが好きな私、「大丈夫、食べます」と言って、持って帰りました。
ピーマン代わりに肉と一緒に炒め、いよいよ食事。
一口食べたら、「ああああああああ!辛!」
えええ?なんで?
もう一口。
辛!
これ、ダメだ、食べれません。辛すぎです。
でも、食べないともったいないから、何とか肉だけ食べました。
以降、そのまま食べることなく、醤油漬けにしています。
辛さ抜群、とてもおいしい。
辛い物好きな方にお勧めです。
でも、そのまま食べるのが勇気が必要です😉

2018年9月9日日曜日

自作簡易フィラメントランアウトセンサー

フィラメントランアウトセンサーとは、3Dプリンターが印刷中、フィラメントがなくなる時、知らせてくれるセンサーとのことです。
基本的に、二種類があります。
ファムウェアと連動して、フィラメントがなくなると印刷を止め、フィラメントの交換を待つタイプ。これはファムウェアの設定が必要です。
スタンドアロン型のフィラメントランアウトセンサーは、フィラメントがなくなると光や音などの警告を出し、知らせます。印刷はそのまま、ユーザーが反応しないとプリント中のものに支障が出ます。でも、ファムウェアの設定を必要しないため、わりと簡単に設置できます。

今回はこのスタンドアロン型のセンサーをDIYしました。
マイクロスイッチでフィラメントの有無を感知し、フィラメントがなくなるとアクティブブザーが鳴ります。それだけで。
アクティブブザーの音が結構うるさいので、フィラメントを交換している間にその音を一時的に中断するために、横の小さいスライドスイッチを付けました。
これをEnder-3という3Dプリンターに使用する予定です!