前言

上一篇是flash FORTH在Digital I/O 的應用,這一篇,來開始攻克 SPI 介面吧。一但搞定 SPI 介面,flash FORTH 就可以有很多豐富的應用惹!

說起 SPI 介面,大家最常拿 Max 7219這顆用 SPI 來溝通的 8x8 LED 矩陣控制器來測試囉。所以順便來用它做個迷你跑馬燈來做測試吧,放在書房裡面看到那字跑啊跑的,其實蠻療癒的呢!(之前有用過 Arduino IDE, 也有用過 Raspberry Pi 做過同樣的東西囉,有興趣也請參考)

 

SPI 簡介

之前就介紹過一次惹,這次為了方便閱讀,跟文章的連貫性,直接複製貼上! 😬

SPI介面的全名是 Serial Peripheral Interface (序列周邊介面),最早是由 Motorola 公司所推出的一種同步全雙工序列介面,它允許兩個裝置之間以同步,全雙工,序列的方式進行高速數據通信。且速度較其他兩個常用的 UART,I2C 介面的速度還要快,所以廣泛的被使用在各種重視傳輸速度的電子裝置上,例如 SD記憶卡,佳能 Canon 相機的 EF接環,數位/類比轉換IC,液晶顯示器,... etc.

SPI 通訊的主軸如下圖所示,其實關鍵是兩的環狀的頭尾相連的8位元位移暫存器,在一個時脈內,頭尾互相交換資料。總共需要四個通訊接腳,定義如下:

MOSI (Master Output Slave Input): 主機往周邊發送訊號的訊號線

MISO (Master Input Slave Output): 周邊往主機發送訊號的訊號線

SS (Slave Select): 周邊通訊選擇 (SPI 可以支援多重周邊通訊),用來指定要連線的週邊設備,邏輯假(Low) 代表選取,邏輯真(High) 代表未選。

SCK (Serial Clock): 主機跟周邊兩邊交換資料時兩邊的時脈基準

700px-SPI_single_slave.svg.png

傳輸的核心其實是透過位於 Master 及 Slave ,數位邏輯電路的「位移暫存器」 (Shift Register) 來完成

SPI01.png

 

Master 透過 SS致能 Digital I/O訊號來告知所要通訊的 Slave

所以多周邊的連接方式如下 (這時候 Master 需要針對每個 Slave 都要有一個 SS 周邊選擇致能控制):

600px-SPI_three_slaves.svg.png

特點:

1. 透過主從的方式支援多重周邊通訊:一台主機可以跟多台周邊對談交換資料。主機藉由對不同周邊的 SS 周邊選擇訊號線的致能,選擇所欲交談的對象。

2. 採用同步的方式來傳輸交換數據:主機須於 SCK 訊號線提供兩周邊對談所需的同步時脈訊號。因為採用時脈來同步雙方數據交換,所以雙方通訊的速度由此時脈訊號的速度來決定,理論上最大傳輸速度沒有限制,實際上可以達到 20 Mbit/sec 的高資料傳輸速率。

3. 全雙工的方式主機跟周邊同時交換資料:在一個時脈週期內, MOSI/MISO 兩條線同時對周邊跟主機交換資料。

時脈極性 CPOL (Clock Polarity):定義idle時時脈訊號的電位基準,低電位 CPOL= 0, 高電位 CPOL= 1

時脈相位 CPHA (Clock Phase):定義資料是由時脈的前緣觸發還是後緣觸發。 CPHA=0 時前緣觸發,觸發時採樣。CPHA=1 時後緣觸發,觸發時採樣。

實際上有定義了四種資料模式:

SPI 模式
資料模式 時脈極性 CPOL 時脈相位 CPHA
MODE 01 0 0
MODE 02 0 1
MODE 03 1 0
MODE 04 1 1

 

Arduino Uno 的 SPI 介面

Arduino Uno 的 ATmega328 微處理器內建 SPI 介面,接腳如下定義:

SS: Pin 10

MOSI : Pin 11

MISO: Pin 12

SCK: Pin 13

要控制多周邊的情況下, 假如 Arduino 是主機(Master),主機需要額外的 digital I/O 來做其他周邊的 SS (Slave Select) 選擇。

 

MAX7219 組裝 8x8 LED陣列:

我們這個迷你跑馬燈,主角是一個 8x8 的 LED 陣列。 這個 LED 陣列總共有 8x8 = 64 個數量龐大的 LED,要控制這麼多的 LED習慣上會採用專門設計的IC來控制。MAX7219 就是這樣的一個控制IC,被設計來控制驅動 8x8 的 LED陣列,或是8個七段顯示器。然後它採用 SPI 介面來跟外界溝通。

所以市面上很容易買到現成已經用 MAX7219 跟 8x8 LED 陣列製作好的模組,透過現成的模組,很方便就可以組成我們的迷你跑馬燈。而控制這種 8x8 LED陣列的主軸,自然轉向如何透過 SPI 通訊介面來跟 MAX7219 溝通!

HipstamaticPhoto-560651276.409329.png

 

MAX7219 的控制:

因爲筆者買到的已經是 MAX7219跟 8x8 LED 矩陣在一起的模組囉,所以細部電路就不管他囉!我們只要專心在如何跟 MAX7219 溝通跟控制就好。

MAX7219 內部一共有14個八位元的暫存器,解說如下

MAX7219 暫存器
暫存器名稱 位址 (16進位) 用途
Digit 0 0x1 LED矩陣第1行內容
Digit 1 0x2 LED矩陣第2行內容
Digit 2 0x3 LED矩陣第3行內容
Digit 3 0x4 LED矩陣第4行內容
Digit 4 0x5 LED矩陣第5行內容
Digit 5 0x6 LED矩陣第6行內容
Digit 6 0x7 LED矩陣第7行內容
Digit 7 0x8 LED矩陣第8行內容
No-Op 0x0 未使用
Decode Mode 0x9 是否啟用BCD解碼 (七段顯示器 only)
Intensity 0xA LED 顯示亮度
Scan Limit 0xB 可顯示的 LED 陣列或七段顯示器的數目
Shutdown 0xC 關閉所有LED,但仍可接收資料
Display Test 0xF 顯示器測試模式開啟(讓所有LED全亮,目視測試誰壞了)

 

MAX7219 的運作方式很簡單,它會不斷的檢視這14個暫存器的內容,根據內容採取對應的控制動作。所以我們只要透過 SPI 介面,根據我們的需求,不斷更新這14個暫存器的內容就可以囉。

 

MAX7219 SPI 協定:

MAX7219 的封包每次 16位元 (2 byte),前 8位元(D7-D0 低位元組)是資料,給暫存器用。後 4位元(D11-D8高位元組)是暫存器位址,最後 4位元未使用(D15-D12 高位元組)。

真實傳送時,須從高位元組D15-D8 (暫存器位址)先傳送,再傳送D7-D0低位元組(8位元資料) - 且每個位元組傳送順序為 MSB First (Big-Endian)

波形的資料模式採用 Mode0: CLK 訊號 Idle Low,MOSI/MISO 前緣觸發採樣。
 

迷你跑馬燈硬體接線

IMG_2514.png

後面照片

HipstamaticPhoto-560736298.385387.png

實際接線

SPI02.png

 

FORTH 語法設計

關於 SPI 的操作

spiMasterInit  以 Master 模式起始 SPI 通訊

spiEnabled, spiDisabled  開啟或關閉硬體SPI 通訊功能

spiMasterMode, spiSlaveMode  設定 SPI 通訊模式為 Master 或 Slave

spiLsbFirst, spiMsbFirst 設定資料於SPI中傳輸的順序,是高位元 MSB 先,還是低位元 LSB 先

spiMode0, spiMode1, spiMode2, sipMode3 設定 SPI 通訊中的訊號模式,有 Mode0, Mode1, Mode2, Mode3 四種

spiCLK/2, spiCLK/4, spiCLK/8, spiCLK/16 ... spiCLK/128  設定 SPI 通訊的速度,為晶片震盪時脈的 /2, /4, /8, /16 ... /128

spi-8M, spi-4M, spi-2M, spi-1M, spi-500K, spi-250K, spi-125K 設定 SPI 通訊的速度,針對 UNO,其基礎震盪時脈 16Mhz, 所以可以有 8Mhz, 4Mhz, 2Mhz, 1Mhz, 500Khz, 250Khz, 125Khz 這些選擇

spiByteTxRx     從 SPI 介面傳送並接收資料

spiByteTx     從 SPI 介面接收資料

 

關於迷你跑馬燈

ScrollChar ( asc --) 給一個 asc code,將其對應的字母進行捲動

例如, 65 ScrollChar 會將字母 ‘A’ 捲動顯示出來

 

Scrolling ( addr n --)

將一個字串進行捲動顯示

例如,  s" Hello World!" Scrolling   會將 "Hello World!" 這串文字以捲動的方式顯示出來。

 

Atmega328 關於 SPI 控制的暫存器

三個主要暫存器: SPCR, SPSR, SPDR

$4c constant SPCR   \ SPI Control Register 控制暫存器
$4d constant SPSR   \ SPI Status Register 狀態暫存器
$4e constant SPDR   \ SPI Data Register 資料暫存器

 

SPCR 控制暫存器,每一 bit 控制 SPI 硬體如下

bit7 SPCR Bit_Def spiInterrupt    \ SPIE: SPI 中斷致能否
bit6 SPCR Bit_Def spiEnable       \ SPE:  SPI 功能打開否
bit5 SPCR Bit_Def spiLsb1st       \ DORD: SPI 資料傳輸次序,1的話LSB先,0的話MSB先
bit4 SPCR Bit_Def spiMaster       \ MSRR: 1的話Master模式,0的話Slave模式
bit3 SPCR Bit_Def spiCPOL         \ CPOL: CPOL 為0或1
bit2 SPCR Bit_Def spiCPHA         \ CPHA: CPHA 為0或1
bit1 SPCR Bit_Def spiClockRate1   \ SPR1: 控制SPI時脈除頻的倍數
bit0 SPCR Bit_Def spiClockRate0   \ SPR2: 控制SPI時脈除頻的倍數

 

SPSR 狀態暫存器,每一 bit 代表 SPI 目前狀態如下

bit7 SPSR Bit_Def spiEndTrans     \ SPIF:  SPI傳輸結束旗號,用這個來知道資料已經傳出否
bit6 SPSR Bit_Def spiWrColision   \ WCOL:  SPI寫入碰撞旗號
bit0 SPSR Bit_Def spi2x           \ SPI2x: 控制SPI時脈除頻的倍數乘上兩倍

 

SPI 控制解說

透過控制 SPCR, SPSR, SPDR 這三個暫存器的資料,就可以控制整個硬體 SPI 的運作

所以

要關掉 SPI,就是將 SPCR 清空每一 bit 設成 0

: spiDisabled   $00 SPCR c!   ;
 

要開啟 SPI,將 bit6 SPCR (spiEnable) 設成 1 (on)

: spiEnabled    spiDisabled     spiEnable on    ;

 

要 MSB First,將 bit5 SPCR (spiLsb1st) 設成 0 (off)

: MsbFirst     spiLsb1st  off ;

 

要 MSB First,將 bit5 SPCR (spiLsb1st) 設成 1 (on)

: LsbFirst     spiLsb1st  on  ;
 

同理,bit4 SPCR (spiMaster) 控制 Master/Slave Mode 

: spiMasterMode   spiMaster  on  ;
: spiSlaveMode    spiMaster  off ;

 

Mode0, Mode1, Mode2, Mode3 四個模式的控制

: spiMode0    spiCPOL off  spiCPHA off  ;
: spiMode1    spiCPOL off  spiCPHA on   ;
: spiMode2    spiCPOL on   spiCPHA off  ;
: spiMode3    spiCPOL on   spiCPHA on   ;

 

SPI 中 CLK 訊號的頻率是靠 CPU 主時鐘的頻率,透過除頻器得到的,除頻器的倍率控制如下

: spiCLK/2   spiClockRate1 off spiClockRate0 off spi2x  on   ;
: spiCLK/4   spiClockRate1 off spiClockRate0 off spi2x  off  ;
: spiCLK/8   spiClockRate1 off spiClockRate0 on  spi2x  on   ;
: spiCLK/16  spiClockRate1 off spiClockRate0 on  spi2x  off  ;
: spiCLK/32  spiClockRate1 on  spiClockRate0 off spi2x  on   ;
: spiCLK/64  spiClockRate1 on  spiClockRate0 off spi2x  off  ;
: spiCLK/128 spiClockRate1 on  spiClockRate0 on  spi2x  off  ;

 

Arduino Uno 的主時鐘頻率為 16Mhz ,所以除頻後得到的 SPI 頻率為

: spi-8M   spiCLK/2   ;
: spi-4M   spiCLK/4   ;
: spi-2M   spiCLK/8   ;
: spi-1M   spiCLK/16  ;
: spi-500K spiCLK/32  ;
: spi-250K spiCLK/64  ;
: spi-125K spiCLK/128 ;

 

Atmega SPI 的運作很簡單,只要往 SPDR 資料暫存器塞資料,硬體就會立刻透過位移暫存器開始與對方交換資料。使用者可以檢查 bit7 SPSR暫存器 (spiEndTrans) 來得知傳送是否結束否。當其為1時傳送結束。此時 SPDR 資料暫存器裡是跟對方交換完畢所送上來對方的新資料。

所以,檢查SPI資料傳送結束否

: spiEndTrans?  spiEndTrans bit@ ;

: spiWait       begin   spiEndTrans?    until    ;

 

傳送並接收一個 byte 的資料

: spiByteTxRx ( c1 -- c2)   SPDR c!   spiWait   SPDR c@    ;

 

只傳送,不接收

: spiByteTx  ( c1 --)    spiByteTxRx  drop   ;

 

最後,也蠻關鍵的 SPI Master Mode 起始程序,小編只是裡面弄錯順序,結果就不會動惹。 Debug 了好幾天哪,真是吃盡苦頭惹!

先設定每個腳位的資料方向跟狀態,然後依序起始這三個SPI暫存器。

: spiMasterInit

   SCK  >OUTPUT  設定資料方向:輸出
   MOSI >OUTPUT  設定資料方向:輸出
   SS   >OUTPUT  設定資料方向:輸出
   MISO <INPUT   設定資料方向:輸入
   
   SCK  ->Low    設定狀態:輸出 Low
   MISO ->High   雖然方向是讀取,但是要設成 pull-high
   SS   ->High   設定狀態:輸出 High
   
   spiEnabled    啟動 SPI 硬體
   spiMasterMode 設定為 Master Mode
   
   SPSR c@ drop  起始觸發一下 SPSR
   SPDR c@ drop  起始觸發一下 SPDR
;

 

 

迷你跑馬燈程式碼解說

首先是 max7219 的 SPI 通訊,利用 spiByteTx 傳送 byte 資料,一次兩個 bytes,先送暫存器位址,再送資料

SS 是邏輯Low ,所以先放 Low 告知 Slave 開始 SPI 傳送。 SPI 規定,傳完資料後假如 SS 繼續維持Low,代表繼續傳輸下一 byte ,直到 SS 為 High 為止。

: Send ( data register --)
   SS ->Low   輸出 Low,要求 Slave 開始接收資料
   spiByteTx  傳送 register
   spiByteTx  傳送 data
   SS ->High  輸出 High,通知 Slave 停止接收資料
;

 

有了 Send 這個重要的指令,就可以很方便地控制 Max7219 惹!

Max7219 暫存器位址

$0 constant NO_OP
( $1 - $8, data for display on each line)
$9 constant DECODE_MODE
$a constant INTENSITY
$b constant SCAN_LIMIT
$c constant SHUTDOWN
$f constant DISPLAY_TEST

 

所以一開始,設定 Max7219 暫存器來起始 Max7219

: init-7219
   spi-1M
   spiMode0

   0      NO_OP        Send
   1      SHUTDOWN     Send
   0      DISPLAY_TEST Send
   1      INTENSITY    Send
   7      SCAN_LIMIT   Send
   0      DECODE_MODE  Send
;

Max7219 暫存器 $1 - $8 8 bytes 的資料,分別對應矩陣上的每行,每個 bit 對應其中的一個點,1的時候亮,0的時候暗。

所以只要更新這八個暫存器的資料,就可以畫出各種圖形。

 

先在 Arduino 的隨機存取記憶體裡建立一個對應的圖形緩衝區,只要隨時透過 SPI 把圖形緩衝區的資料更新到 Max7219 的暫存器,就可以同步畫出各種圖形囉。前面要記得加上 ram 指令,要求 allot 是運作在 ram 裡面,而不是 flash 或是 eeprom

ram

create ScreenBuffer 8 chars allot  ( buffers for 8x8 picture)

 

將緩衝區的資料透過 SPI  Send 指令更新到 max7219 的圖形資料暫存器中。

: UpdateScreen  \ update buffer data to 7219 
   8
   for ScreenBuffer r@ chars + c@ ( data)     計算位址並取出緩衝區裡的圖形資料
       r@ 1+                      ( register) 計算7219圖形資料暫存器位址
       Send                                   SPI 傳送
   next
;

 

ScrollScreen 圖形捲動指令,需給定 P.addr 參數

P.addr 指向圖形所在的位址,每個圖形一共 8 bytes。 這個指令會根據圖形資料以捲動的方式,慢慢地將圖形由右邊慢慢往左捲入進去。

捲動的方式很簡單呀, 只要把 ScreenBuffer 裡從0開始數,從第1到第7 byte共7個bytes資料往前移動一個byte (利用cmove指令),再 UpdateScreen 就好啦,就會看到所有圖形往左移,然後第一行資料被蓋掉。

然後最後一行再給它餵上從圖形位址所給的新的資料,這樣就好啦。

: ScrollScreen ( P.addr --) \ P.addr is the address of your 8x8 picture data
    8 
    for   ( P.addr)
       ( 把圖形暫存區裡的資料往前搬移一行,1byte)
       ScreenBuffer char+    ScreenBuffer   7   cmove
       
       ( 從P.addr取出新資料,放到圖形暫存區的末端)
       dup c@   ScreenBuffer 7 chars +     c!
         
       char+  ( P.addr 往後移動 1 byte,指向下一行資料)
       
       UpdateScreen   PausedTime ms  ( 以新的資料,更新8x8點陣顯示)       
    next  drop        
;

 

接下來是字型資料,依照 ASC Code 的順序,從32開始。這部分的純資料我喜歡放到 EEPROM 裡面,所以前面加上 eeprom 關鍵字,要求編寫入 EEPROM。

eeprom

create fonts

   00 c, 00 c, 00 c, 00 c, 00 c, 00 c, 00 c, 00 c, \ ' ' - 32
   00 c, 06 c, 5f c, 5f c, 06 c, 00 c, 00 c, 00 c, \ '!' - 33

...

...

 

 

為了彈性,字型資料的位址指標是利用一個 ram 裡的變數 'fonts 來指定

  0 value  'fonts         \ pointer pointed to the address of the font table

 

所以,捲動特定 ASC Code 字元的指令

: ScrollChar ( ascii --)
    32 max 127 min              ( range check)
    32 -  8 chars *  'fonts  +  ( calc actual address of 8x8 font pic data)
    
    ScrollScreen
;

 

然後是捲動一整個字串的指令,Scrolling

給定字串位址 addr 跟長度 n ,用個 for next 掃過字串中的每個字元,然後用 ScrollChar 來捲動顯示。

這裡比較麻煩的是, for next 的 index 是倒數的,所以要稍微用堆疊運算的技巧算一下,把它轉成正數的。

: Scrolling ( addr n --)
    1- tuck  1+
    for              ( n addr) 
       over r@ -     ( n addr index) \ index指向要顯示的字元
       chars over + c@   ScrollChar  \ 將字元取出並捲動顯示
    next 2drop
;

 

 

最後,我最愛的紐西蘭歌手海莉 Hayley Westenra 的美妙歌曲, Hana (夏川里美的花心)

 

: Hana
   spiMasterInit
   init-7219
   100   to  PausedTime
   fonts to 'fonts
   
   begin  
      s" Hana - Hayley Westenra "                Scrolling   p
      s" I see the river in the daylight "       Scrolling   p
      s" Glistening as it flows its way "        Scrolling   p
      s" I see the people travelling "           Scrolling   p
      s" Through the night and through the day " Scrolling   p
      s" I see their paths colliding "           Scrolling   p
      s" Water drops and golden rays "           Scrolling   p
      s" Flowers bloom, oh, flowers bloom "      Scrolling   p
      s" On this blessed day "                   Scrolling   p
      s" Let the tears fall back "               Scrolling   p
      s" Let the laughter through "              Scrolling   p
      s" One day, oh, one day "                  Scrolling   p 
      p p p
   again
;

 

實際執行狀況,正確無誤。

 

 

 

最後都OK 了,可以透過下面指令將 Hana 的執行位址存入 turnkey 開機起始向量(延遲指令)中,這樣一開機就會立刻執行囉。隨時插上電,這一串字就會跑出來,放在客廳,或是書房,臥室,真的很療癒呢!🥰🥰

' Hana is turnkey

 

再一些實況紀錄照片

IMG_5356D.png

IMG_5360D.png

 

 

 

====

原始程式碼列表

程式碼1 - Arduino Pin

\
\  Flash FORTH  Arduino Uno  digital I/O
\
\      Frank Lin 2020.10.15
\

--uno_dio--

marker --uno_dio--

\
\ bit masks
\


%00000001 constant bit0
%00000010 constant bit1
%00000100 constant bit2
%00001000 constant bit3
%00010000 constant bit4
%00100000 constant bit5
%01000000 constant bit6
%10000000 constant bit7


\
\ Atmega328 Digital I/O Registers
\

#37 constant PortB
\ #36 constant DDRB
\ #35 constant PinB

#40 constant PortC
\ #39 constant DDRC
\ #38 constant PinC

#43 constant PortD
\ #42 constant DDRD
\ #41 constant PinD

 

: Pin_Def ( mask Port "Name" --)
   create swap c, c,
   does>  dup  c@        ( mask)
          swap char+ c@  ( Port)
;


\
\  Arduino Uno with ATmega328 Pin definations
\


flash

bit0 PortD  Pin_Def Pin0
bit1 PortD  Pin_Def Pin1
bit2 PortD  Pin_Def Pin2
bit3 PortD  Pin_Def Pin3
bit4 PortD  Pin_Def Pin4
bit5 PortD  Pin_Def Pin5
bit6 PortD  Pin_Def Pin6
bit7 PortD  Pin_Def Pin7

bit0 PortB  Pin_Def Pin8
bit1 PortB  Pin_Def Pin9
bit2 PortB  Pin_Def Pin10
bit3 PortB  Pin_Def Pin11
bit4 PortB  Pin_Def Pin12
bit5 PortB  Pin_Def Pin13

bit0 PortC  Pin_Def Pin14
bit1 PortC  Pin_Def Pin15
bit2 PortC  Pin_Def Pin16
bit3 PortC  Pin_Def Pin17
bit4 PortC  Pin_Def Pin18
bit5 PortC  Pin_Def Pin19


\
\ UART
\

Pin0        Pin_Def RxD
Pin1        Pin_Def TxD


\
\ SPI
\

Pin10       Pin_Def SS
Pin11       Pin_Def MOSI
Pin12       Pin_Def MISO
Pin13       Pin_Def SCK

 

\
\ I2C
\

Pin18      Pin_Def SDA
Pin19      Pin_Def SCL

 

\
\   Digital I/O Access Codes
\


: >OUTPUT ( mask port --)   \ set the direction of digital I/O to output
   1-     ( DDR register)
   mset   ( set to High = OUTPUT)
;

: <INPUT  ( mask port --)   \ set the direction of digital I/O to input
   1-     ( DDR register)
   mclr   ( set to Low = INPUT)
;

: ->High ( mask port --)   \ put digital I/O to High
   mset
;

: ->Low  ( mask port --)   \ put digital I/O to Low
   mclr
;

: Pin@ ( mask port -- status)   \ read the state of digital I/O, 0=false
   2-     ( Pin register)
   mtst   ( read the state)
;

 

 

程式碼2 - 迷你跑馬燈

 

\
\  8x8 LED Matrix Control - Arduino Uno
\
\      Frank Lin  2020.10.25
\


--spi--

marker --spi--

: Bit_Def    Pin_Def ;

: on   mset ;

: off  mclr ;

: bit@ mtst ;

 

\
\  SPI Defination
\


\
\  SPI Registers
\

flash

$4c constant SPCR   \ SPI Control Register
$4d constant SPSR   \ SPI Status Register
$4e constant SPDR   \ SPI Data Register


bit7 SPCR Bit_Def spiInterrupt    \ SPIE: SPI Interrupt Enable
bit6 SPCR Bit_Def spiEnable       \ SPE:  SPI Enable Flag
bit5 SPCR Bit_Def spiLsb1st       \ DORD: Data Order Bit
bit4 SPCR Bit_Def spiMaster       \ MSRR: Master/SLave Select Bit
bit3 SPCR Bit_Def spiCPOL         \ CPOL: Clock Polarity
bit2 SPCR Bit_Def spiCPHA         \ CPHA: Clock Phase
bit1 SPCR Bit_Def spiClockRate1   \ SPR1: SPI Clock Rate Select
bit0 SPCR Bit_Def spiClockRate0   \ SPR2: SPI Clock Rate Select


bit7 SPSR Bit_Def spiEndTrans     \ SPIF:  SPI End of Transmit Flag
bit6 SPSR Bit_Def spiWrColision   \ WCOL:  Write Colision Flag
bit0 SPSR Bit_Def spi2x           \ SPI2x: Double SPI Speed


: LsbFirst     spiLsb1st  on  ;
: MsbFirst     spiLsb1st  off ;

: spiMasterMode   spiMaster  on  ;
: spiSlaveMode    spiMaster  off ;

: spiDisabled   $00 SPCR c!   ;
: spiEnabled    spiDisabled spiEnable  on    ;

: spiMode0    spiCPOL off  spiCPHA off  ;
: spiMode1    spiCPOL off  spiCPHA on   ;
: spiMode2    spiCPOL on   spiCPHA off  ;
: spiMode3    spiCPOL on   spiCPHA on   ;


: spiCLK/2   spiClockRate1 off spiClockRate0 off spi2x  on   ;
: spiCLK/4   spiClockRate1 off spiClockRate0 off spi2x  off  ;
: spiCLK/8   spiClockRate1 off spiClockRate0 on  spi2x  on   ;
: spiCLK/16  spiClockRate1 off spiClockRate0 on  spi2x  off  ;
: spiCLK/32  spiClockRate1 on  spiClockRate0 off spi2x  on   ;
: spiCLK/64  spiClockRate1 on  spiClockRate0 off spi2x  off  ;
: spiCLK/128 spiClockRate1 on  spiClockRate0 on  spi2x  off  ;


\
\ arduino uno
\

: spi-8M   spiCLK/2   ;
: spi-4M   spiCLK/4   ;
: spi-2M   spiCLK/8   ;
: spi-1M   spiCLK/16  ;
: spi-500K spiCLK/32  ;
: spi-250K spiCLK/64  ;
: spi-125K spiCLK/128 ;

 

: spiEndTrans?  spiEndTrans bit@ ;

: spiWait       begin   spiEndTrans?    until    ;

: spiByteTxRx ( c1 -- c2)   SPDR c!   spiWait   SPDR c@    ;

: spiByteTx  ( c1 --)    spiByteTxRx  drop   ;


: spiMasterInit

   SCK  >OUTPUT
   MOSI >OUTPUT
   SS   >OUTPUT
   MISO <INPUT
   
   SCK  ->Low  
   MISO ->High
   SS   ->High   
   
   spiEnabled
   spiMasterMode
   
   SPSR c@ drop
   SPDR c@ drop
;

 

\ MAX 7219


marker --max7219--


: Send ( data register --)
   SS ->Low
   spiByteTx
   spiByteTx
   SS ->High
;

flash

$0 constant NO_OP
( $1 - $8, data for display on each line)
$9 constant DECODE_MODE
$a constant INTENSITY
$b constant SCAN_LIMIT
$c constant SHUTDOWN
$f constant DISPLAY_TEST


: init-7219
   
   spi-1M
   spiMode0
   

   0      NO_OP        Send
   1      SHUTDOWN     Send
   0      DISPLAY_TEST Send
   1      INTENSITY    Send
   7      SCAN_LIMIT   Send
   0      DECODE_MODE  Send
;


\ screen buffer mapped to 7219 registers of 8x8 LED matrix

ram

create ScreenBuffer 8 chars allot  ( buffers for 8x8 picture)

100 value   PausedTime    \ control the speed of scrolling
  0 value  'fonts         \ pointer pointed to the address of the font table

 
: UpdateScreen  \ update buffer data to 7219 
   8
   for ScreenBuffer r@ chars + c@   ( data)
       r@ 1+                        ( register)
       Send
   next
;
   
\ scrolling data inside screen buffer

: ScrollScreen ( P.addr --) \ P.addr is the address of your 8x8 picture data
    8 
    for   ( P.addr)
       ( move one line forward inside screen buffer)
       ScreenBuffer char+    ScreenBuffer   7   cmove
       
       ( supply new data from P.addr to the end of screen buffer)
       dup c@   ScreenBuffer 7 chars +     c!
         
       char+  ( step P.addr)
       
       UpdateScreen   PausedTime ms  ( refresh 8x8 LED Matrix)
       
    next  drop        
;


\ scroll a character

: ScrollChar ( ascii --)
    32 max 127 min              ( range check)
    32 -  8 chars *  'fonts  +  ( calc actual address of 8x8 font pic data)
    
    ScrollScreen
;


\
\  Syntax Examples:
\
\  S" Happy Birthday Hayley Westenra" Scrolling
\  Scrolling" Happy Birthday Hayley Westenra!"
\


\ scroll a counted string

: Scrolling ( addr n --)
    1- tuck  1+
    for              ( n addr) 
       over r@ -     ( n addr index)
       chars over + c@   ScrollChar
    next 2drop
;

 


\ fonts data for 8x8 LED Matrix
\ the order is as in ascii code started from 32

marker --fonts--

hex

eeprom

create fonts

   00 c, 00 c, 00 c, 00 c, 00 c, 00 c, 00 c, 00 c, \ ' ' - 32
   00 c, 06 c, 5f c, 5f c, 06 c, 00 c, 00 c, 00 c, \ '!' - 33
   00 c, 07 c, 07 c, 00 c, 07 c, 07 c, 00 c, 00 c, \ '"'
   14 c, 7f c, 7f c, 14 c, 7f c, 7f c, 14 c, 00 c, \ '#'
   24 c, 2e c, 6b c, 6b c, 3a c, 12 c, 00 c, 00 c, \ '$'
   46 c, 66 c, 30 c, 18 c, 0c c, 66 c, 62 c, 00 c, \ '%'
   30 c, 7a c, 4f c, 5d c, 37 c, 7a c, 48 c, 00 c, \ '&'
   04 c, 07 c, 03 c, 00 c, 00 c, 00 c, 00 c, 00 c, \ '''
   00 c, 1c c, 3e c, 63 c, 41 c, 00 c, 00 c, 00 c, \ '('
   00 c, 41 c, 63 c, 3e c, 1c c, 00 c, 00 c, 00 c, \ ')'
   08 c, 2a c, 3e c, 1c c, 1c c, 3e c, 2a c, 08 c, \ '*'
   08 c, 08 c, 3e c, 3e c, 08 c, 08 c, 00 c, 00 c, \ '+'
   00 c, 80 c, e0 c, 60 c, 00 c, 00 c, 00 c, 00 c, \ ' c,'
   08 c, 08 c, 08 c, 08 c, 08 c, 08 c, 00 c, 00 c, \ '-'
   00 c, 00 c, 60 c, 60 c, 00 c, 00 c, 00 c, 00 c, \ '.'
   60 c, 30 c, 18 c, 0c c, 06 c, 03 c, 01 c, 00 c, \ '/'
   3e c, 7f c, 71 c, 59 c, 4d c, 7f c, 3e c, 00 c, \ '0'
   40 c, 42 c, 7f c, 7f c, 40 c, 40 c, 00 c, 00 c, \ '1'
   62 c, 73 c, 59 c, 49 c, 6f c, 66 c, 00 c, 00 c, \ '2'
   22 c, 63 c, 49 c, 49 c, 7f c, 36 c, 00 c, 00 c, \ '3'
   18 c, 1c c, 16 c, 53 c, 7f c, 7f c, 50 c, 00 c, \ '4'
   27 c, 67 c, 45 c, 45 c, 7d c, 39 c, 00 c, 00 c, \ '5'
   3c c, 7e c, 4b c, 49 c, 79 c, 30 c, 00 c, 00 c, \ '6'
   03 c, 03 c, 71 c, 79 c, 0f c, 07 c, 00 c, 00 c, \ '7'
   36 c, 7f c, 49 c, 49 c, 7f c, 36 c, 00 c, 00 c, \ '8'
   06 c, 4f c, 49 c, 69 c, 3f c, 1e c, 00 c, 00 c, \ '9'
   00 c, 00 c, 66 c, 66 c, 00 c, 00 c, 00 c, 00 c, \ ':'
   00 c, 80 c, e6 c, 66 c, 00 c, 00 c, 00 c, 00 c, \ ';'
   08 c, 1c c, 36 c, 63 c, 41 c, 00 c, 00 c, 00 c, \ '<'
   24 c, 24 c, 24 c, 24 c, 24 c, 24 c, 00 c, 00 c, \ '='
   00 c, 41 c, 63 c, 36 c, 1c c, 08 c, 00 c, 00 c, \ '>'
   02 c, 03 c, 51 c, 59 c, 0f c, 06 c, 00 c, 00 c, \ '?'
   3e c, 7f c, 41 c, 5d c, 5d c, 1f c, 1e c, 00 c, \ '@'
   7c c, 7e c, 13 c, 13 c, 7e c, 7c c, 00 c, 00 c, \ 'A'
   41 c, 7f c, 7f c, 49 c, 49 c, 7f c, 36 c, 00 c, \ 'B'
   1c c, 3e c, 63 c, 41 c, 41 c, 63 c, 22 c, 00 c, \ 'C'
   41 c, 7f c, 7f c, 41 c, 63 c, 3e c, 1c c, 00 c, \ 'D'
   41 c, 7f c, 7f c, 49 c, 5d c, 41 c, 63 c, 00 c, \ 'E'
   41 c, 7f c, 7f c, 49 c, 1d c, 01 c, 03 c, 00 c, \ 'F'
   1c c, 3e c, 63 c, 41 c, 51 c, 73 c, 72 c, 00 c, \ 'G'
   7f c, 7f c, 08 c, 08 c, 7f c, 7f c, 00 c, 00 c, \ 'H'
   00 c, 41 c, 7f c, 7f c, 41 c, 00 c, 00 c, 00 c, \ 'I'
   30 c, 70 c, 40 c, 41 c, 7f c, 3f c, 01 c, 00 c, \ 'J'
   41 c, 7f c, 7f c, 08 c, 1c c, 77 c, 63 c, 00 c, \ 'K'
   41 c, 7f c, 7f c, 41 c, 40 c, 60 c, 70 c, 00 c, \ 'L'
   7f c, 7f c, 0e c, 1c c, 0e c, 7f c, 7f c, 00 c, \ 'M'
   7f c, 7f c, 06 c, 0c c, 18 c, 7f c, 7f c, 00 c, \ 'N'
   1c c, 3e c, 63 c, 41 c, 63 c, 3e c, 1c c, 00 c, \ 'O'
   41 c, 7f c, 7f c, 49 c, 09 c, 0f c, 06 c, 00 c, \ 'P'
   1e c, 3f c, 21 c, 71 c, 7f c, 5e c, 00 c, 00 c, \ 'Q'
   41 c, 7f c, 7f c, 09 c, 19 c, 7f c, 66 c, 00 c, \ 'R'
   26 c, 6f c, 4d c, 59 c, 73 c, 32 c, 00 c, 00 c, \ 'S'
   03 c, 41 c, 7f c, 7f c, 41 c, 03 c, 00 c, 00 c, \ 'T'
   7f c, 7f c, 40 c, 40 c, 7f c, 7f c, 00 c, 00 c, \ 'U'
   1f c, 3f c, 60 c, 60 c, 3f c, 1f c, 00 c, 00 c, \ 'V'
   7f c, 7f c, 30 c, 18 c, 30 c, 7f c, 7f c, 00 c, \ 'W'
   43 c, 67 c, 3c c, 18 c, 3c c, 67 c, 43 c, 00 c, \ 'X'
   07 c, 4f c, 78 c, 78 c, 4f c, 07 c, 00 c, 00 c, \ 'Y'
   47 c, 63 c, 71 c, 59 c, 4d c, 67 c, 73 c, 00 c, \ 'Z'
   00 c, 7f c, 7f c, 41 c, 41 c, 00 c, 00 c, 00 c, \ '['
   01 c, 03 c, 06 c, 0c c, 18 c, 30 c, 60 c, 00 c, \ backslash
   00 c, 41 c, 41 c, 7f c, 7f c, 00 c, 00 c, 00 c, \ ']'
   08 c, 0c c, 06 c, 03 c, 06 c, 0c c, 08 c, 00 c, \ '^'
   80 c, 80 c, 80 c, 80 c, 80 c, 80 c, 80 c, 80 c, \ '_'
   00 c, 00 c, 03 c, 07 c, 04 c, 00 c, 00 c, 00 c, \ '`'
   20 c, 74 c, 54 c, 54 c, 3c c, 78 c, 40 c, 00 c, \ 'a'
   41 c, 7f c, 3f c, 48 c, 48 c, 78 c, 30 c, 00 c, \ 'b'
   38 c, 7c c, 44 c, 44 c, 6c c, 28 c, 00 c, 00 c, \ 'c'
   30 c, 78 c, 48 c, 49 c, 3f c, 7f c, 40 c, 00 c, \ 'd'
   38 c, 7c c, 54 c, 54 c, 5c c, 18 c, 00 c, 00 c, \ 'e'
   48 c, 7e c, 7f c, 49 c, 03 c, 02 c, 00 c, 00 c, \ 'f'
   98 c, bc c, a4 c, a4 c, f8 c, 7c c, 04 c, 00 c, \ 'g'
   41 c, 7f c, 7f c, 08 c, 04 c, 7c c, 78 c, 00 c, \ 'h'
   00 c, 44 c, 7d c, 7d c, 40 c, 00 c, 00 c, 00 c, \ 'i'
   60 c, e0 c, 80 c, 80 c, fd c, 7d c, 00 c, 00 c, \ 'j'
   41 c, 7f c, 7f c, 10 c, 38 c, 6c c, 44 c, 00 c, \ 'k'
   00 c, 41 c, 7f c, 7f c, 40 c, 00 c, 00 c, 00 c, \ 'l'
   7c c, 7c c, 18 c, 38 c, 1c c, 7c c, 78 c, 00 c, \ 'm'
   7c c, 7c c, 04 c, 04 c, 7c c, 78 c, 00 c, 00 c, \ 'n'
   38 c, 7c c, 44 c, 44 c, 7c c, 38 c, 00 c, 00 c, \ 'o'
   84 c, fc c, f8 c, a4 c, 24 c, 3c c, 18 c, 00 c, \ 'p'
   18 c, 3c c, 24 c, a4 c, f8 c, fc c, 84 c, 00 c, \ 'q'
   44 c, 7c c, 78 c, 4c c, 04 c, 1c c, 18 c, 00 c, \ 'r'
   48 c, 5c c, 54 c, 54 c, 74 c, 24 c, 00 c, 00 c, \ 's'
   00 c, 04 c, 3e c, 7f c, 44 c, 24 c, 00 c, 00 c, \ 't'
   3c c, 7c c, 40 c, 40 c, 3c c, 7c c, 40 c, 00 c, \ 'u'
   1c c, 3c c, 60 c, 60 c, 3c c, 1c c, 00 c, 00 c, \ 'v'
   3c c, 7c c, 70 c, 38 c, 70 c, 7c c, 3c c, 00 c, \ 'w'
   44 c, 6c c, 38 c, 10 c, 38 c, 6c c, 44 c, 00 c, \ 'x'
   9c c, bc c, a0 c, a0 c, fc c, 7c c, 00 c, 00 c, \ 'y'
   4c c, 64 c, 74 c, 5c c, 4c c, 64 c, 00 c, 00 c, \ 'z'
   08 c, 08 c, 3e c, 77 c, 41 c, 41 c, 00 c, 00 c, \ ''
   00 c, 00 c, 00 c, 77 c, 77 c, 00 c, 00 c, 00 c, \ '|'
   41 c, 41 c, 77 c, 3e c, 08 c, 08 c, 00 c, 00 c, \ ''
   02 c, 03 c, 01 c, 03 c, 02 c, 03 c, 01 c, 00 c, \ '~'
  
   fonts to 'fonts

decimal

flash

\ Let's have some funs

: Happy-Birthday
  spiMasterInit
   init-7219
   100   to  PausedTime
   fonts to 'fonts
   
   begin    
      s" Happy Birthday Hayley Westenra !!!" Scrolling
      key? 
   until
;

 

: p  1000 ms ;

: Hana
   spiMasterInit
   init-7219
   100   to  PausedTime
   fonts to 'fonts
   
   begin  

      s" Hana - Hayley Westenra "                Scrolling   p
      s" I see the river in the daylight "       Scrolling   p
      s" Glistening as it flows its way "        Scrolling   p
      s" I see the people travelling "           Scrolling   p
      s" Through the night and through the day " Scrolling   p
      s" I see their paths colliding "           Scrolling   p
      s" Water drops and golden rays "           Scrolling   p
      s" Flowers bloom, oh, flowers bloom "      Scrolling   p
      s" On this blessed day "                   Scrolling   p
      s" Let the tears fall back "               Scrolling   p
      s" Let the laughter through "              Scrolling   p
      s" One day, oh, one day "                  Scrolling   p
      s" The Flowers will reach full bloom "     Scrolling   p 

      p p p
   again
;

 

Xxxx

arrow
arrow
    創作者介紹
    創作者 ohiyooo2 的頭像
    ohiyooo2

    早安,苦命工程師的胡言亂語

    ohiyooo2 發表在 痞客邦 留言(0) 人氣()