2016年10月02日

Sitaraプロセッサ(41): タイマ/GPIO/割込みをまとめて動作

AM3359の割り込みなども調査が完了しました。 
   昨日の内容はこちら → Sitaraプロセッサ(40): サンプルのIRQ_Handlerを調査


まとめてみたいと思います。

1)   INTC_Init();を呼び出し
  → これにより割り込みコントローラの初期化が実施できます。

2) タイマの設定と割り込み有効化
   タイマを有効化して、
  /*Enable Interface Clock*/
  CM_PER_L4LS_CLKSTCTRL_bit.CLKTRCTRL = 2;
  CM_PER_L4LS_CLKCTRL_bit.MODULEMODE = 2;
  CM_PER_GPIO1_CLKCTRL_bit.MODULEMODE = 2;
  /*Wait clocks to get active*/
  while(CM_PER_GPIO1_CLKCTRL_bit.IDLEST ||
        CM_PER_L4LS_CLKCTRL_bit.IDLEST);
 
  CM_WKUP_CLKSTCTRL_bit.CLKTRCTRL = 2; 
  CM_WKUP_TIMER0_CLKCTRL_bit.MODULEMODE = 2;
  while(CM_WKUP_TIMER0_CLKCTRL_bit.IDLEST);
 
 
  DMTIMER0_TIOCP_CFG_bit.SOFTRESET = 1;
  while(DMTIMER0_TIOCP_CFG_bit.SOFTRESET);
 
 
 
  DMTIMER0_TCLR_bit.AR = 1;
  DMTIMER0_TLDR = 0xFFF00000;
  DMTIMER0_TCRR =DMTIMER0_TLDR; 
  //////////
 
  DMTIMER0_IRQENABLE_SET = DMTIMER_IRQ_OVF_FLAG;
 
  INTC_IntInstall(Timer0Handler,INT_TINT0,15,INTC_INT_IRQ);
  INTC_IntEnable(INT_TINT0,INTC_ENABLE);
 
 
  /* START TIMER */
  DMTIMER0_TCLR_bit.ST = 1;
  __enable_interrupt( );


3。割り込みハンドラの準備
 サンプルの記述をIRQ_Handlerに関してはそのまま利用しました。
 そして、タイマ0割り込みを以下のようにしました。
int flag=0;
void Timer0Handler(void)
{
  if ( flag == 0 ) {
    GPIO1_CLEARDATAOUT = D1;
    flag =1;
  } else {
    GPIO1_SETDATAOUT = D1;
    flag = 0;
  }
 
  /*clear interrupt*/
  DMTIMER0_IRQSTATUS = DMTIMER_IRQ_OVF_FLAG;
}

これで、すこしゆっくりですが、LEDが点滅しています。

良かったよかった。
自分としては、Cortex-A8ですが、基本を押さえれば良いということが確認できました。




  

ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする

2016年10月01日

Sitaraプロセッサ(40): サンプルのIRQ_Handlerを調査

昨日、サンプルのInitTimer0の調査を実施しました。 


最後にIRQ_Handlerの内容を確認したいと思います。
__arm __nested __irq void IRQ_Handler(void)
{

/*Save current prioriry level*/ 
uint32_t Priority = INTC_THRESHOLD;
/*get  interrupt service routine*/                    
IntrFunc_t isr =IsrTbl[INTC_SIR_IRQ_bit.ACTIVEIRQ];   

 
  INTC_THRESHOLD = INTC_IRQ_PRIORITY_bit.IRQPRIORITY;  /*Disable Interrupts with currnet and lower priority*/

  /*Reset IRQ output and enable new IRQ generation*/
  INTC_CONTROL = INTC_CONTROL_NEWIRQAGR;
  /*Data Synchronization Barrier*/
  __MCR(15, 0, 0, 7, 10, 4);
 
  __enable_irq();
   
  if(isr)
  {
    (isr)();                            /*Call installed interrupt service routine*/
  }
  else
  {/*Interrupt routine not installed*/
    while(1);
  }
  __disable_irq();

  INTC_THRESHOLD = Priority;             /*Restore Interrupts priority*/
  /*Data Synchronization Barrier*/
  __MCR(15, 0, 0, 7, 10, 4);
 
}


まず、Cortex-A8では割込みは2種類あり、IRQかFIQのどちらになります。
割込みではレジスタの退避などが必要なため、割込みハンドラをC言語で定義するためには、コンパイラに教えてやる必要があります
そのため__arm __nested __irq void IRQ_Handler(void) という記述の__armと__nestedと__irqは割込みハンドラを定義するための物です。
このIRQ_HandlerはIRQ割り込みを処理するための割込みハンドラになります。

まず、このIRQ_Handlerでは多重割込みを認めていますので、割り込みレベルの調整を実施しています。
以下の記述がそうなります。
uint32_t Priority = INTC_THRESHOLD;

・・・
  INTC_THRESHOLD = INTC_IRQ_PRIORITY_bit.IRQPRIORITY;  /*Disable Interrupts with currnet and lower priority*/
・・・
  INTC_THRESHOLD = Priority;             /*Restore Interrupts priority*/

また、このIRQ_HandlerにはIRQと設定した割込みがすべて入ってきますので、割り込み要因によって分岐する必要があります。
それが、以下の記述です。
 IntrFunc_t isr =IsrTbl[INTC_SIR_IRQ_bit.ACTIVEIRQ];   
 ・・・
  if(isr)
  {
    (isr)();                            /*Call installed interrupt service routine*/
  }
  else
  {/*Interrupt routine not installed*/
    while(1);
  }

最初割り込みコントローラおINTC_SIR_IRQを見に行っていますが、以下のレジスタです。
SitaraA0115.png
このレジスタを見ることで現在の割込み要因が解りますので、その要因から割込みハンドラを呼び出しています。


組込みでよく使われるマイコンはベクタ型の割込みコントローラが使われることが多いのですが、ARMですとARM7、9、11やCortex-Aは自分で割り込み要因から振り分ける必要があります。


ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする

2016年09月30日

Sitaraプロセッサ(39): サンプルのInitTimer0を調査

昨日AM3359のサンプルで割込みの初期化処理を見ました → Sitaraプロセッサ(38): サンプルの初期化INTC_Initを調査

今日はサンプルの関数InitTimer0を見てみます。
まずは関数の全体を以下に示しておきましょう。
 *************************************************************************/
void InitTimer0(uint32_t tps)
{
  /*Enable DMTIMER0 clocks*/
  CM_WKUP_CLKSTCTRL_bit.CLKTRCTRL = 2;
  CM_WKUP_TIMER0_CLKCTRL_bit.MODULEMODE = 2;
  /*Wait clock to get active*/
  while(CM_WKUP_TIMER0_CLKCTRL_bit.IDLEST);
  /*Reset Timer*/
  DMTIMER0_TIOCP_CFG_bit.SOFTRESET = 1;
  /*wait reset*/
  for(volatile uint32_t i = 0; 100000 > i ;i++);
  /**/
  DMTIMER0_TSICR_bit.POSTED = 0;
  /*Auto reload*/
  DMTIMER0_TCLR_bit.AR = 1;
  /*Set tick per second*/
  DMTIMER0_TLDR = 0-(32000/tps);
  DMTIMER0_TCRR =DMTIMER0_TLDR;
  /*Timer 0 interrup install*/
  INTC_IntInstall(Timer0Handler,INT_TINT0,15,INTC_INT_IRQ);
  /*Enable Overflow intr*/
  DMTIMER0_IRQENABLE_SET = DMTIMER_IRQ_OVF_FLAG;
  INTC_IntEnable(INT_TINT0,INTC_ENABLE);
  /*Start Timer*/
  DMTIMER0_TCLR_bit.ST = 1;
}

ここで、割込みに関係するのは、赤くマークしたINTC_IntInstallとINTC_IntEnableです。
この2つの関数をさらに追いかけてみましょう。
void INTC_IntInstall(IntrFunc_t isr, uint32_t index,
                     uint32_t priority, intc_type_t type)
{
__intc_ilr_bits * Ilr;

  /* Sanitary check */
  if(INT_MCSPI1INT < index)
  {
    return;
  }
  Ilr = (__intc_ilr_bits *)(&INTC_ILR0 + index);
  /*Set Interrupt priority*/
  Ilr->PRIORITY = priority & 0x3F;
  /*Set interrupt type*/
  Ilr->FIQNIRQ = type;
  /*Set interrupt service routine*/
  IsrTbl[index] = isr;
}

関数の引数を見ると第1引数が割込みハンドラ、第2引数が割込み番号、第3引数が優先度、第4引く数が割り込みのタイプになります。
割込み番号はAM3359のマニュアルに示されています。サンプルではTIMER0の割込みを使っているのでマークしておきました。
SitaraA0112.png

さて関数の記述を見ていきます。
1. __intc_ilr_bits * Ilr;
   これ解りにくいですが、ポインタ変数の定義です。
/* INTC_ILRm */
typedef struct {
   __REG32 FIQNIRQ         : 1;
   __REG32                 : 1;
   __REG32 PRIORITY        : 6;
   __REG32                 :24;
} __intc_ilr_bits;
割込みコントローラにILRというレジスタがあります。このILRは割込み数だけ用意されており、FIQNIRQビットでそれぞれの割込みがIRQにはいるのか?FIQにはいるのかを指定します。またプライオリティもここで設定できます。
SitaraA0113.png

2.   Ilr = (__intc_ilr_bits *)(&INTC_ILR0 + index);
 で、実際のINTC_ILRのアドレスを取得しています。そのためindexも使って計算しています。

3.   Ilr->PRIORITY = priority & 0x3F;
  引数からあたえられたpriorityをILRに設定します。

4.   Ilr->FIQNIRQ = type;
  FIQ またはIRQを使うか設定します。ここでは、IRQです。

5.   IsrTbl[index] = isr;
  TIMER0の割込みハンドラを登録します。


こんどは、関数INTC_IntEnableを見てみます。
void INTC_IntEnable(uint32_t index, intc_enable_t enable)
{
  /* Sanitary check */
  if(INT_MCSPI1INT < index)
  {
    return;
  }
 
  if(INTC_ENABLE == enable)
  {/*Enable interrupt*/
    *(&INTC_MIR_CLEAR0 + (8*index/32)) = (1<<(index%32));
  }
  else
  {/*Disable interrupt*/
    *(&INTC_MIR_SET0 + (8*index/32)) = (1<<(index%32));
  }
}


割込みコントローラに対して、タイマ0割り込みを有効にする記述となります。レジスタが用意されていますので、CLEARするかSETすれば良いだけです。

SitaraA0114.png
なんと見えてきました。




ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする

2016年09月29日

Sitaraプロセッサ(38): サンプルの初期化INTC_Initを調査

Sitara AM3359で割込みプログラムを作成するためには、まず調べることにしました。
  昨日の話”Sitaraプロセッサ(37): さて割込みはどうなっている?”はこちら → http://ewarmjp.seesaa.net/article/441809446.html

サンプルを見ると割込みを使うための初期化関数がINTC_Initのようです。
関数全体を貼っておきます。
void INTC_Init(void)
{
  __disable_interrupt();

  /*Reset INTC*/
  INTC_SYSCONFIG_bit.SOFTRESET = 1;
  while(!INTC_SYSSTATUS_bit.RESETDONE);
  /**/
  INTC_THRESHOLD = 0xFF;
  /*Clear interrupt service routine table*/
  for(uint32_t i = 0; 128 > i; i++)
  {
    IsrTbl[i] = 0;
  }
 
  __enable_interrupt();
}

一行ずつ読んでいきます。
1.  __disable_interrupt();
  これはIARが用意している組込み関数です。割り込みを禁止します。
 Cortex-A8では割込みは大きく分けてIRQとFIQがありますが、この__disable_interrupt( )は両方の割込みを禁止します。
 もし、IRQだけ停止させたい場合には、__disable_irq( )を使用します。



2. INTC_SYSCONFIG_bit.SOFTRESET = 1;
  これは割込みコントローラをリセットするものです。レジスタの説明を持ってきました。
特に、現在は起動した後に、デバッガでRAMにソフトを展開して実行しているため割込みコントローラの設定を初期化しておくことは重要です。そうしないと、予想しない動きをします。
SitaraA0109.png

3.   while(!INTC_SYSSTATUS_bit.RESETDONE);
 これは2でかけたリセットが終了したかを見ています。。
SitaraA0110.png

4.   INTC_THRESHOLD = 0xFF;
  割込みスレショルドを指定するレジスタです。ただ0xFFを指定するとスレショルドを無効にするそうです。
SitaraA0111.png

 じゃあ、プライオリティはどうなっているのか?というと最高の優先度は0x0、最低の優先度が0x7Fです。
 INTC_THRESHOLDと同じか低い割込みはマスクされます。
 ただ0x0だけは特殊で、このINTC_THRESHOLDではマスクできません。

5. IsrTbl[i] = 0;
 これはIsrTblの定義から見た方がよいですね。割込み関数を定義する場所になります。
typedef void(*IntrFunc_t)(void);
static IntrFunc_t IsrTbl[128];

勝手に書いた関数ポインタでなぜ割込みハンドラとなるか?ですが、Cortex-A8では割込みはIRQハンドラもしくはFIQハンドラに入ってきます。
そのため、IRQハンドラからこのIsrTblの関数ポインタを呼び出しているだけです。実際のコードを以下で見てみましょう。
__arm __nested __irq void IRQ_Handler(void)
{

/*Save current prioriry level*/ 
uint32_t Priority = INTC_THRESHOLD;
/*get  interrupt service routine*/                    
IntrFunc_t isr =IsrTbl[INTC_SIR_IRQ_bit.ACTIVEIRQ];   

 
  INTC_THRESHOLD = INTC_IRQ_PRIORITY_bit.IRQPRIORITY;  /*Disable Interrupts with currnet and lower priority*/

  /*Reset IRQ output and enable new IRQ generation*/
  INTC_CONTROL = INTC_CONTROL_NEWIRQAGR;
  /*Data Synchronization Barrier*/
  __MCR(15, 0, 0, 7, 10, 4);
 
  __enable_irq();
   
  if(isr)
  {
    (isr)();                            /*Call installed interrupt service routine*/
  }
  else
  {/*Interrupt routine not installed*/
    while(1);
  }
  __disable_irq();

  INTC_THRESHOLD = Priority;             /*Restore Interrupts priority*/
  /*Data Synchronization Barrier*/
  __MCR(15, 0, 0, 7, 10, 4);
 
}


6.   __enable_interrupt();
 1でかけた割込み禁止をこれで解除しています。


解りましたか? 明日は、個別の設定を見てみます。




ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする

2016年09月28日

Sitaraプロセッサ(37): さて割込みはどうなっている?

これまででBeaglebone Black上のSitara AM3359を使って、GPIOやタイマは動かすことが出来ました。
  昨日まではこちら → http://ewarmjp.seesaa.net/article/441194438.html

これから割り込みを使えるようにしてみたいと思いますが、壱から勉強するのは面倒です。
今回もサンプルを使って勉強します。
EWARMのインフォメーションセンタでサンプルから探してみます。
SitaraA0107.png
2つのプロジェクトがあるので、Getting Startedを見ます。
SitaraA0108.png

重要なのはmain関数から、以下の2つの関数が呼び出されているところです。
  INTC_Init();
  InitTimer0(16);

それぞれの中身を見ると、
void INTC_Init(void)
{
  __disable_interrupt();

  /*Reset INTC*/
  INTC_SYSCONFIG_bit.SOFTRESET = 1;
  while(!INTC_SYSSTATUS_bit.RESETDONE);
  /**/
  INTC_THRESHOLD = 0xFF;
  /*Clear interrupt service routine table*/
  for(uint32_t i = 0; 128 > i; i++)
  {
    IsrTbl[i] = 0;
  }
 
  __enable_interrupt();
}


void INTC_IntInstall(IntrFunc_t isr, uint32_t index, uint32_t priority, intc_type_t type)
{
__intc_ilr_bits * Ilr;

  /* Sanitary check */
  if(INT_MCSPI1INT < index)
  {
    return;
  }
  Ilr = (__intc_ilr_bits *)(&INTC_ILR0 + index);
  /*Set Interrupt priority*/
  Ilr->PRIORITY = priority & 0x3F;
  /*Set interrupt type*/
  Ilr->FIQNIRQ = type;
  /*Set interrupt service routine*/
  IsrTbl[index] = isr;
}

これを読み解くのが一番早そうです。





ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする

2016年09月27日

Sitaraプロセッサ(36): タイマー動作が気に要らない

昨日AM 3359のタイマを動かすことが出来ました。 → Sitaraプロセッサ(35): タイマー記述し動作確認

しかし、気に入らない点があります。
SitaraA0103.png

TLDRに代入したところですが、すでにTCRRでタイマの値がカウントアップされています。
これがなぜかと調べると、すでにタイマがスタートされているのです。
SitaraA0104.png

なんで、こうなっているか?ですが、すこし説明が面倒です。
今の私のBeagleboneは、BeagleboneのブートからLINUXのコード(ROM)にはまったく手を加えていません。
そのため、電源を入れるとこのROMから動作を開始しますが、その途中でICEから停止してRAMにプログラムを書き込み実行しています。
なので、プログラムで明示的に書き換えない限り初期化されません。また、さらに一度EWARMで接続しているので、プログラムを変更して書き換えるときもリセットしません。そのため、前の設定がそのまま残っています。

どうすると良いかと考えたのですが、タイマのレジスタにリセットする機能があります。
SitaraA0105.png

それで実際にコードを追加してみました。
  CM_WKUP_TIMER0_CLKCTRL_bit.MODULEMODE = 2;
  while(CM_WKUP_TIMER0_CLKCTRL_bit.IDLEST);

 
  DMTIMER0_TIOCP_CFG_bit.SOFTRESET = 1;
  while(DMTIMER0_TIOCP_CFG_bit.SOFTRESET);
 
  DMTIMER0_TLDR = 0xFFF00000;
  DMTIMER0_TCRR =DMTIMER0_TLDR;
 
  DMTIMER0_TCLR_bit.AR = 1;
 
  /* START TIMER */
  DMTIMER0_TCLR_bit.ST = 1;

するとこんな感じで気持ちよく動かすことが出来ました。
SitaraA0106.png

良かったです!



ラベル:Sitara AM3359
posted by EWARMJP at 12:00| Comment(0) | TrackBack(0) | TI(Texas Instruments) | このブログの読者になる | 更新情報をチェックする