前言
上一篇是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): 主機跟周邊兩邊交換資料時兩邊的時脈基準
傳輸的核心其實是透過位於 Master 及 Slave ,數位邏輯電路的「位移暫存器」 (Shift Register) 來完成
Master 透過 SS致能 Digital I/O訊號來告知所要通訊的 Slave
所以多周邊的連接方式如下 (這時候 Master 需要針對每個 Slave 都要有一個 SS 周邊選擇致能控制):
特點:
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 時後緣觸發,觸發時採樣。
實際上有定義了四種資料模式:
資料模式 | 時脈極性 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 溝通!
MAX7219 的控制:
因爲筆者買到的已經是 MAX7219跟 8x8 LED 矩陣在一起的模組囉,所以細部電路就不管他囉!我們只要專心在如何跟 MAX7219 溝通跟控制就好。
MAX7219 內部一共有14個八位元的暫存器,解說如下
暫存器名稱 | 位址 (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 前緣觸發採樣。
迷你跑馬燈硬體接線
後面照片
實際接線
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
再一些實況紀錄照片
====
原始程式碼列表
程式碼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
留言列表