2019年9月30日 星期一

DSP TI TMS320F28335 I2C設置


I2C由SDA在收發資料,由SCL來傳送資料的Clock,Clock讓I2C傳送端與接收端可以
同步,每一個Clock代表一個bit。如下圖,TM320320F28335包含了control、status、
interrupt等暫存器,讓使用者可以藉由設置或讀取這這些暫存器來客制化I2C功能。

I2C發送與接收
當CPU要從SDA資料線傳送資料出去,是將資料寫入I2CDXR,I2CDXR會再將資料
轉到I2CXSR後,發送中斷信號XRDY,讓CPU知道資料已經被發送出去。

CPU要從SDA接收資料,資料是先被存到I2CRSR,在I2CRSR將資料更新到I2CDRR
後,發出中斷信號RRDY,讓CPU知道I2C module接收到新的資料,可以去讀取。


























I2C Clock設定
當TMS320F28335被設為I2C Master,要設置I2C SCL的Clock頻率,從下圖Figure 3
看到從Device input clock經過PLLCR,再到I2C Moudle IPSC、ICCL/ICC這三個除
頻器,最後產生出Master clock做為SCL的clock。TMS320F28335支援I2C頻率
10K~400KHz,為了要符合這個頻率區間,Moudule clock需要在7-12MHz。
在設定IPSC時,I2CMDR裡的IRS要設為"0"(reset state),如果在IRS為"1"時,修
改IPSC是無效的。
















Master clock公式
要得到Tmst(Master clock period),就要先得到Tmod(module clockperiod)、ICCL
、ICCH與d的值。而module clock由input clock除以 (IPSC+1)得出。另外d (delay)
的值如Table 15, 可以得知與IPSC的值有關,為5、6、7其中之1。

IPSC由暫存器I2CPSC.bit7:0來設定,範圍是 0~255。當IPSC設為"0",就表示
module clock=I2C input clock。在TI的Example code裡,I2C input clock有100MHz
、150MHz兩種設定,為了讓Module clock降到10MHz,符合7~12MHz的範圍,
在I2C input clock為100MHz時,就設IPSC為9,在150MHz時,設IPSC為14。
再來因為IPSC>1,所以d(delay)=5。

Tmod周期時間為module clock的倒數,Tmmod=1/10MHz=0.1us,再設置ICCL與
ICCH就可以得到Tmst。在TI的Example code裡,設置ICCL=10, ICCH=5,代入
公式,可以得到Tmst=Tmod x [(10+5) + (5+5)]=0.1us x 25= 2.5us,最後得出
Master clock= 1/ Tmst= 400KHz。









從Figure22可以看到,Tmst是Tmod所計算出來的。










I2C中斷事件
I2C有7個中斷事件,在Figure13可以看到,每個中斷事件,可以由I2CIER去設置
enable/disable,被設為disable的中斷事件,在事件發生時,就不會去通知CPU。
I2CSTR(I2C status register)裡面所對應的bit會會被設"1"。

XRDYINT:用來通知CPU,原來I2CDXR內資料已經傳送出去,可以再寫入新的
                      資料到I2CDXR。這個中斷不適用於FIFO模式。
RRDYINT:用來通知CPU,I2CDRR接收到新的資料,CPU可以來讀取。這個中
                      斷不適用於FIFO模式。
ARDYINT:當I2C Port做為Master,ARDYINT用來通知CPU,前一段I2C命令已
                      終止,可以再寫入新的命令到I2C module register。
NACKINT:當I2C Port做為Master,在傳送資料給接收端,接收端要在ACK/NACK
                       bit將SDA訊號下拉,來表示ACK,有接收到資料。如果接收端沒反
                       應ACK,NACKINT就會被SET,通知CPU,接收端沒接收到資料。
                   
ALINT:Arbitration-lost為仲裁丟失,當I2C BUS上有兩個或多個I2C Master,企圖
                去發送資料時,但I2C Bus上,只能有一個Master,所以需要去仲裁是那個
                I2C Master搶到發言權。在TMS320F28335的I2C Master Port沒搶到發信權,
                ALINT就會被SET來通知CPU,並由I2C Master轉為Slaver。
SCDINT:在I2C傳送資料的最後,會有個Stop bit,讓I2C Bus上其他的I2C Module在
                   ,在偵測到這個stop事件,可以知道資料傳送結束,否則I2C Bus就是在
                   busy狀態。SCDINT用來通知CPU,有Stop condition被偵測到。
AASINT:當I2C Port做為Slave,在I2C Bus上接收到另一個I2C Master發送出來位址
                   資料是這個I2C Port所設定的Slave位址(I2COAR),也就是這個命令是要
                   傳給自已的 ,則ASSINT會被SET,通知CPU,要去接收後面由I2C Master
                   傳來的資料。
,



I2C相關暫存器




















I2COAR:設置在做為Slaver時的address位址。
I2CIER:用來設置那些中斷是有效的。
I2CSTR:用來判斷I2C的狀態,其中有些暫存器要寫入"1"來清除狀態旗標。
I2CCLKL/I2CCLKH:用來設置I2C Master clock的周期時間與頻率。
I2CCNT:用來設置I2C Master是要傳多少Byte或接收傳輸多少Byte的data。
I2CDRR:CPU讀取這個暫存器來接收另一端傳送來的資料。
I2CSAR:在做為I2C Master,設置I2CSAR來設定要操作的Slave address。
I2CMDR:控制I2C進入Start、Stop、Nack、Repeak、Reset等模式,在I2C
                   收發資料的過程中,需要去設定I2CMDR裡面的bits。
I2CISRC:CPU在收收到中斷通知後,會先讀取I2CISRC來得知是那個
                   中斷事件發生,再去執行對應的處理程序。讀完I2CISRC後,
                    在I2CSTR內的Flag會被清除,但I2CSTR的ARDY、RRDY、
                    XRDY是需要寫入"1"去清除的。
I2CDXR:CPU寫入資料到這個暫存器,來傳送資料給另一端。
I2CEMDR:設置BCM (Backwards compatibility mode),在做為Slave端
                      並在發送資料時,BCM設置為"0" or "1"會影響I2CSTR
                      暫存器裡XRDY, XSMT的動作方式。
I2CPSC:設置I2C input clock的除頻多少來轉為I2C module clock。
I2CFFTX/I2CFFRX:在FIFO模式下,TX與RX的控制與狀態暫存器。




void I2CA_Init(void)
{
   // Initialize I2C
   I2caRegs.I2CMDR.all = 0x0000; //將I2C模式設為Reset/Disable mode 
   I2caRegs.I2CFFTX.all = 0x0000; // 將FIFO模式關閉,Reset FFTX。。
   I2caRegs.I2CFFRX.all = 0x0040; // Reset FFRX, FFRX中斷功能關閉。
   #if (CPU_FRQ_150MHZ)             // 當CPU頻率(SYSCLKOUT)為150MHz,就設置
        I2caRegs.I2CPSC.all = 14;   // PSC為14,module clk (150/15 = 10MHz)
   #endif
   #if (CPU_FRQ_100MHZ)             //當CPU頻率(SYSCLKOUT)為150MHz,就設置
     I2caRegs.I2CPSC.all = 9;     //PSC為9,module clk (100/10 = 10MHz)
   #endif
   I2caRegs.I2CCLKL = 10;             // 注意:不能設為"0"
   I2caRegs.I2CCLKH = 5;              // 注意:不能設為"0"
   I2caRegs.I2CIER.all = 0x24;        // 啟動SCD與ARDY中斷的偵測
   I2caRegs.I2CMDR.all = 0x0020; // 設置I2C peripheral(裝置)離開Reset mode,
                                //可以接收Host在I2C Bus發送的命令。   
   I2caRegs.I2CFFTX.all = 0x6000;     // 啟動I2C FIFO模式與TX FIFO運作。
   I2caRegs.I2CFFRX.all = 0x2040;     // 動作 RXFIFO,清除RXFFINT旗標。
   return;

}




Reference:
1.TI TMS320x2833x, 2823x Inter-Integrated Circuit (I2C) Module Reference Guide (Rev. B)


















2019年9月24日 星期二

DSP TI TMS320F28335 GPIO設置


TI TMS320F28335 的GPIO,比較特別的是多了Qualification功能,另外可以用
GPxSET、GPxClear、GPxToggle來設置gpio輸出。下面是它的方塊圖與暫存器
例表與解釋。




































相關的暫存器如下






























GPACTRL:設定在Qualification(限定)功能的取樣周期。
GPAQSEL:設定在Qualification的取樣次數。
GPAMUX:設定各個GPIO pin是做為GPIO或是其它I/O pin功能,例如下面Table50裡
                     所定義的GPIO14與GPIO15 pin,除了可以被定義成"00"=>GPIO功能,各
                     別可以被定義為不同的I/O功能,如PWM、SCI、McBSP、eCAN等,但
                      每個GPIO可以被定義的I/O功能是不同的,需要在GPxMUX Table去確認                                     。
GPADIR:每個GPIO pin在做為GPIO功能時,可以各別定義是Input或Output pin,初始
                   設定是"0"=>Input。
GPAPUD:設置各個GPIO pin內部的Pullup電阻是否開啟,如下圖Table65,有些GPIO   
                    GPIO初始內部Pullup電阻是開啟的,有些GPIO是關閉的。雖然GPIO在系統
                    程式開始運作後,可以各別定義各個GPIO輸出,但在系統運作前,GPIO
                    是無法被程式所控制的。如果希這個GPIO與外部線路的節點在是拉High的
                    ,就可以找初始內部Pullup電阻是開啟的GPIO pin,或是直接在線路上,加
                    一個上拉電阻。
GPIOXINT1SEL:XINT是外部中斷,GPIOXINT1SEL可以設置GPIO0~31,其中的那一
                               PIN做為XINT1功能。
GPIONMISEL:XNMI是外部不可遮罩式中斷,可以設置GPIO0~31其中一PIN為NMI。
GPIOLPMSEL:一般外部中斷是無法在Low power mode(Halt, Standby mode)來喚醒系統
                             的,但GPIOLPMSEL可設置GPIO0~31其中一個,在Low power mode可以
                             用來外部觸發,喚醒系統回到工作模式。
GPADAT:這個暫存器有bit0~31,對映GPIO0~31。讀取這個暫存器可以知道GPIO0~31
                    PIN的輸入狀態是"0"還是"1",無論這個PIN在GPAMUX是被設為GPIO還是
                    其他的I/O功能。寫入這個暫存器可以設置GPIO0~31的輸出為"1"或是
                     "1"。
GPASET:這個暫存器有bit0~31,對映GPIO0~31對其中一個bit設為"1"就可以將它對映
                   的GPIO設為輸出High,但它要是在GPIO Output模式。對GPASET其它的bit寫
                   入"0",不會有任何影響,。
GPACLEAR:這個暫存器有bit0~31,對映GPIO0~31。對其中一個bit設為"1"就可以將它對映
                         的GPIO設為輸出Low,但它要是在GPIO Output模式。對GPACLEAR其它的bit
                         寫入"0",不會有任何影響。
GPATOGGLE:這個暫存器有bit0~31,對映GPIO0~31。對其中一個bit設為"1"就可以將它對映
                         的GPIO設為輸出反轉,但它要是在GPIO Output模式。例如讓原本輸出為High
                         轉為輸出Low。對GPATOGGLE其它的bit寫入"0",不會有任何影響。










GPIO輸入限定功能(Input Qualication)
GPIO在做為輸入時,可以開啟限定功能,在連續取樣3次或6次的High或Low,才
判斷輸入準位。例如要開啟GPIO3的限定功能就將GPIO Port A(GPIO0~31) GPAQSEL1的
Bit7:6設為"01"=>Qualification using 3 samples或"10"=>Qualification using 6 samples.

取樣時間間隔由GPACTRL的Bit0~7來設定,從1xTSYSCLKOUT 到510x TSYSCLKOUT
TSYSCLKOUT是SYSCLKOUT的倒數,SYSCLKOUT為150MHz,TSYSCLKOUT則為6.67ns
。GPIO3屬於GPIO0~7,由QUALPRD0來設定,如下圖的例子,在設定GPAQSEL1
為"1,0",設QUALPRD0為"01",可以得到取樣窗口為Tw(IQSW)=5x2xTSYSCLKOUT 。
6次取樣,只有5次取樣間隔,所以取樣窗口為5x2xTSYSCLKOUT=67ns。當出現(A)這個
脈衝時,會被限定器Qualifier給忽略到,直到後面連續取樣到6次"1",限定器的輸出
才會被拉到"1"。

在GPAQSEL1的設定,還有"00"=>與SYSCLKOUT同步、"11"=>非同步模式。
在"00"這個設定,取樣就只需要1次TSYSCLKOUT的時間。在"11"這個設定,GPIO做為
SCI、SPI、eCAN、I2C或是ePWM輸入訊號,它的取樣時間會是一次取樣時間加上
TSYSCLKOUT,所以當QUALPRDx設為"01",限定器響應輸入訊號的時間為2xTSYSCLKOUT
+TSYSCLKOUT














Reference:
1.TI TMS320x2833x, 2823x System Control and Interrupts Reference Guide (Rev. D)











2019年9月3日 星期二

DSP TI TMS320F28335 最簡單ADC功能設置


TI TMS320F28335的ADC要如何設置,下面有一個簡單的範例幫助大家
了解,請參考下面說明。

 TMS320F28335有一個12 bit ADC,有兩路的S/H(取樣保持),有16個取樣
通道。這樣可以用一個ADC取樣到16個訊號,這16個訊號源為ADCINA0
~ADCINA7與ADCINB0~ADCINB7,配合Sequencer(排序器),將這16個訊
號源排序,經過MUX開關切換,讓訊號源依序進到ADC進行轉換。





























Cascaded mode(串聯模式)
在Autosequencer(自動排序),去設定CONV00~CONV15各別是對應那個
ADCINXX,等到開始進行轉換,就會從CONV00對應的ADCINXX開始
進行,依序到CONV15。



ADC設定流程
1.對ADC設定參數
#先設定HSPCLK,HSPCLK = SYSCLKOUT/2*ADC_MODCLK2
   在下面的程式範例初始SYSCLKOUT為150MHz,設定MODCLK2為"5",
   可以得到HSPCLK=150/(2*5)=15MHZ
#再來設定ADC模組的Clock,ADC module clock = HSPCLK/ADC_CKPS,
   在設定ADC_CLKPS=1,ADC clock=15MHz/(2*1) = 7.5MHz
#設定取樣維持時脈(SHCLK),ACQP_PS=SHCLK+1,設定SHCLK=15,
  表示ACQ_PS=16個ADC Clock

2.寫入暫存器
#因為System clock的設定暫存器是受保護的,要修改暫存器去設定HSPCLK
  前,需要加EALLOW來解除保護,更改完後,再寫EDIS來恢復保護。
  HSPCLK修改=>  SysCtrlRegs.HISPCP.all = ADC_MODCLK;
#寫入ADC暫存器,如前面描述的,設定ADC_SHCLK與ADC_CKPS,得到
  ADC clock為7.5MHz,取樣時脈為15個ADC Clock。
     AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
     AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS
  設置ADC運作模式,如下面程式範例,設定SEQ_CASC=1,將ADCINA0~
   ADCINA7與ADCINB0~ADCINB7,16個訊號源串接。在這個實驗,只用
   一個訊號源,所以設定SEQ1.bit.CONV00為ADCINA0,
     AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;       
     AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;  
   設置CONT_RUN,表示為連續模式,當Autosequence裡的訊號源都完成ADC
   轉換後,Autosequence的指標就會直接回到第一筆訊號源,等待觸發,在觸
   發後,從第一筆訊號源依序進行ADC轉換。但如果CONT_RUN為"0",在
   Autosequence依序執行ADC轉換,指標會停在最後一筆訊號源,要設置
   AD_CTRL2->RST_SEQx,才能讓Sequence序列回到第一筆。
   AdcRegs.ADCTRL1.bit.CONT_RUN = 1;     
#要觸發ADC轉換,如下方表格ADCTRL2->SOC_SEQ1裡所示,有SW、ePWM
  、EXT3種方式。SW就如下面這個命令,由軟體直接設置ADCTRL2裡第13個bit
   SOC_SEQ1, 就會依序將Sequence1內設定的訊號源進行ADC轉換。
   AdcRegs.ADCTRL2.all = 0x2000;
 
3.讀出ADC轉換結果:
   當ADC進行轉換,就要等待它轉換結束,將數值讀出來。所以會用While迴圈
   ,當Sequence1內的訊號完成ADC轉換,ADCST狀態暫存器裡的INT_SEQ1被設
   為"1",再來將這個中斷Flag清除後,就可以將ADC轉換的資料,讀出來。在這
   個例子,由於只用到CONV00, 所以只有一個ADCINA信琥源的數據,被存在
ADCRESULT0,
   while (AdcRegs.ADCST.bit.INT_SEQ1== 0) {} 
   AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
   showdata=AdcRegs.ADCRESULT0;


程式範例
void delay_loop(void);
#define ADC_MODCLK 0x5                                                    
#define ADC_CKPS   0x1     
#define ADC_SHCLK  0xf   
Uint16 showdata;

int main(void)
{
     InitSysCtrl();
     EALLOW;
     SysCtrlRegs.HISPCP.all = ADC_MODCLK;
     EDIS;
     DINT;
     InitPieCtrl();
     IER = 0x0000;     
     IFR = 0x0000;
      InitPieVectTable();
      InitAdc();  // For this example, init the ADC
       // Specific ADC setup for this example:
          AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
          AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;
          AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;        // 1
          AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;  
          AdcRegs.ADCTRL1.bit.CONT_RUN = 1;       
          AdcRegs.ADCTRL2.all = 0x2000;

          for(;;)
          {
          while (AdcRegs.ADCST.bit.INT_SEQ1== 0) {} // 等待中断
          AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
          showdata=AdcRegs.ADCRESULT0;
          delay_loop();
          }
}

void delay_loop()
{
    long      i;
    for (i = 0; i < 4500000; i++) {}
}



















Reference:
1.http://www.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=spru812a
    => TMS320x2833x, 2823x Analog-to-Digital Converter (ADC) Module Reference Guide (Rev. A)