DS80C400微處理器的網(wǎng)絡(luò)功能使其成為設(shè)計(jì)簡單以太網(wǎng)揚(yáng)聲器的自然選擇。通過使用處理器ROM內(nèi)置的TCP/IP堆棧,用8051匯編編寫的應(yīng)用程序可以輕松地從網(wǎng)絡(luò)讀取流音頻數(shù)據(jù),并使用該數(shù)據(jù)驅(qū)動(dòng)數(shù)模轉(zhuǎn)換器(DAC),為一組揚(yáng)聲器提供線路電平輸出。本應(yīng)用筆記介紹了運(yùn)行支持以太網(wǎng)的簡單揚(yáng)聲器所需的硬件設(shè)計(jì)和軟件。
系統(tǒng)概述
軟件
在頂層,應(yīng)用程序由一臺(tái)主機(jī)組成,通過網(wǎng)絡(luò)連接將未壓縮的音頻(如WAV文件中的數(shù)據(jù))發(fā)送到DS80C400,DS1C<>監(jiān)聽和播放音頻數(shù)據(jù)。圖<>顯示了該系統(tǒng)的框圖。
圖1.系統(tǒng)框圖。
必須有兩個(gè)軟件應(yīng)用程序才能使該系統(tǒng)工作。一個(gè)應(yīng)用程序必須在主機(jī)上運(yùn)行,并將音頻數(shù)據(jù)發(fā)送到DS80C400。另一個(gè)應(yīng)用程序必須在DS80C400上運(yùn)行并播放音頻數(shù)據(jù)。
主機(jī)應(yīng)用程序在此系統(tǒng)中的工作很容易。它必須從 WAV 文件中讀取原始音頻數(shù)據(jù)并通過網(wǎng)絡(luò)發(fā)送。由于主機(jī)上沒有使用大量處理能力,因此它也執(zhí)行其他一些工作,例如流控制和簡單的數(shù)據(jù)格式化。
DS80C400上的應(yīng)用稍微復(fù)雜一些。它需要通過網(wǎng)絡(luò)接收音頻數(shù)據(jù),并以指定的采樣率將該數(shù)據(jù)推送到音頻電路。
接收音頻數(shù)據(jù)是在循環(huán)中實(shí)現(xiàn)的,該循環(huán)等待音頻數(shù)據(jù),并在音頻數(shù)據(jù)可用時(shí)將其寫入循環(huán)緩沖區(qū)。當(dāng)它接收新數(shù)據(jù)時(shí),它還必須維護(hù)一個(gè)指向緩沖區(qū)中有效數(shù)據(jù)末尾的指針,以便應(yīng)用程序不會(huì)播放無效數(shù)據(jù)。
揚(yáng)聲器應(yīng)用的第二部分是將數(shù)據(jù)推送到音頻電路的部分。音頻數(shù)據(jù)被饋送到數(shù)模轉(zhuǎn)換器,該轉(zhuǎn)換器反過來驅(qū)動(dòng)普通的計(jì)算機(jī)揚(yáng)聲器。由于常規(guī)時(shí)序?qū)σ纛l應(yīng)用至關(guān)重要,因此應(yīng)用的這一部分作為定時(shí)器中斷實(shí)現(xiàn)。圖 2 顯示了應(yīng)用程序的循環(huán)和計(jì)時(shí)器部分如何通過循環(huán)音頻緩沖區(qū)進(jìn)行交互。
圖2.循環(huán)音頻緩沖區(qū)。
硬件
圖3所示為音頻電路示意圖,可連接至TINIm400驗(yàn)證模塊或基于DS80C400的定制設(shè)計(jì)。對于這個(gè)項(xiàng)目,揚(yáng)聲器應(yīng)用程序是在最初為網(wǎng)絡(luò)攝像機(jī)設(shè)計(jì)的電路板上開發(fā)的,并進(jìn)行了一些小的修改。
圖3.硬件框圖。
在此配置中,數(shù)模轉(zhuǎn)換器提供 0 至 2V 的輸出。由于線路電平揚(yáng)聲器輸入為±1V,因此揚(yáng)聲器的接地連接到1V。本電路使用的數(shù)模轉(zhuǎn)換器為MAX542。1,其精度為 16 位。串行數(shù)據(jù)可以通過DS80C400的串行端口傳遞到DAC,這比以編程方式切換時(shí)鐘和數(shù)據(jù)引腳要快得多。MAX542具有一條片選線,在串行負(fù)載期間必須保持低電平,負(fù)載信號(Load DAC)必須在所有串行數(shù)據(jù)寫入后保持低電平。
主機(jī)應(yīng)用程序:發(fā)送未壓縮的音頻
主機(jī)應(yīng)用程序是一個(gè)名為 SendDataTCP 的 Java? 類。它是一個(gè)Java應(yīng)用程序,讀取PCM編碼的WAV文件,執(zhí)行一些簡單的格式化,并通過TCP連接將音頻樣本塊發(fā)送到DS80C400。
該程序假設(shè)正在讀取的WAV文件包含立體聲,16位數(shù)據(jù),以44.1kHz的采樣率播放。但是,該應(yīng)用程序支持發(fā)送 44.1、22.05 和 11.025kHz 的采樣率,因此音頻數(shù)據(jù)可能需要重新格式化。假設(shè)WAV文件中的數(shù)據(jù)為16位立體聲,因此每個(gè)樣本由4個(gè)字節(jié)組成(通道2為1字節(jié),通道2為2字節(jié))。如果DS80C400需要單聲道數(shù)據(jù)而不是立體聲數(shù)據(jù),則僅從WAV文件中提取一個(gè)通道。如果采樣率低于44.1kHz,則跳過某些樣本。例如,如果DS80C400需要采樣率為22.05kHz的立體聲數(shù)據(jù),則SendDataTCP程序?qū)l(fā)送2字節(jié)的通道1數(shù)據(jù),發(fā)送2字節(jié)的通道2數(shù)據(jù),然后跳過下一個(gè)樣本。如果預(yù)計(jì)單聲道數(shù)據(jù)頻率為22.05kHz,則SendDataTCP程序?qū)l(fā)送2字節(jié)的通道1數(shù)據(jù),跳過通道2部分,然后跳過整個(gè)下一個(gè)樣本。
在發(fā)送數(shù)據(jù)之前,必須再執(zhí)行兩次轉(zhuǎn)換。首先,必須將示例從有符號數(shù)據(jù)轉(zhuǎn)換為無符號數(shù)據(jù)。WAV文件包含表示-1至1之間電壓的有符號數(shù)據(jù),但MAX542接受表示0至2之間電壓的無符號數(shù)據(jù)。請注意,由于電路為揚(yáng)聲器提供1V的虛擬地,因此所需的轉(zhuǎn)換是簡單地在WAV文件中定義的電壓上增加1 V。由于輸入值8000十六進(jìn)制代表MAX1輸出的542V,因此需要為每個(gè)8000位采樣增加16十六進(jìn)制。請注意,這與切換樣本的高位的操作相同。表 1 顯示了來自 WAV 文件的單個(gè) 16 位樣本、所需電壓、未改變樣本產(chǎn)生的電壓以及 改變后的樣本將產(chǎn)生的電壓。
表 1.改變音頻樣本以實(shí)現(xiàn)所需的電壓輸出
16 位音頻樣本(十六進(jìn)制) | 所需電壓 | 來自未改變樣品的電壓 | 更改的樣本 | 來自改變樣品的電壓 |
0000 | 1.00 | 0.00 | 8000 | 1.00 |
7FFF | 2.00 | 1.00 | FFFF | 2.00 |
8000 | 0.00 | 1.00 | 0000 | 0.00 |
4000 | 1.50 | 0.50 | C000 | 1.50 |
C000 | 0.50 | 1.50 | 4000 | 0.50 |
必須發(fā)生的第二個(gè)轉(zhuǎn)換是位翻轉(zhuǎn)操作。DS80C400上的串行端口首先寫入最低有效位,但MAX542期望數(shù)據(jù)最高有效位優(yōu)先。此操作是使用簡單的查找表執(zhí)行的。
數(shù)據(jù)以80字節(jié)塊的形式發(fā)送到DS400C1400 - 該尺寸可提供最佳性能。數(shù)據(jù)流控制是通過跟蹤上一秒內(nèi)發(fā)送的數(shù)據(jù)量并將其與每秒預(yù)期發(fā)送的數(shù)據(jù)量進(jìn)行比較來執(zhí)行的。例如,采樣率為22.05kHz的單聲道數(shù)據(jù)每秒將產(chǎn)生44,100字節(jié)。如果 SendDataTCP 程序在過去 44 毫秒內(nèi)發(fā)送了 500,800 字節(jié),它將休眠大約 200 毫秒。DS80C400使用超過400kB的緩沖器,相當(dāng)于幾秒鐘的音頻數(shù)據(jù)。因此,準(zhǔn)確的計(jì)時(shí)在SendDataTCP程序中很重要,但并不重要。一些變化是可以接受的。
請注意,SendDataTCP程序通常會(huì)盡可能快地發(fā)送數(shù)據(jù)。如果程序由于在最后一秒發(fā)送了太多數(shù)據(jù)而從未暫停,則可能是數(shù)據(jù)速率過高,應(yīng)用程序無法處理。這可能是網(wǎng)絡(luò)流量過多的結(jié)果。
DS80C400:初始化揚(yáng)聲器應(yīng)用
DS80C400的應(yīng)用完全用8051匯編編寫。請注意,也可以使用 Keil 的編譯器在 C 中實(shí)現(xiàn)應(yīng)用程序。2,或在 Java 中使用 TINI? 運(yùn)行時(shí)環(huán)境3.該應(yīng)用程序足夠小,因此在匯編中編寫它并不是一項(xiàng)艱巨的任務(wù)。
在可能的情況下,揚(yáng)聲器應(yīng)用程序利用了ROM中的功能未占用或更改的資源。DS80C400有4個(gè)數(shù)據(jù)指針,其中只有一個(gè)不作系統(tǒng)更改。前兩個(gè)數(shù)據(jù)指針被所有函數(shù)廣泛使用,尤其是對于復(fù)制操作。第四個(gè)數(shù)據(jù)指針在某些網(wǎng)絡(luò)例程中使用,但始終保留。從不使用第三個(gè)數(shù)據(jù)指針。由于驅(qū)動(dòng)揚(yáng)聲器的中斷需要是高優(yōu)先級中斷,因此第四個(gè)數(shù)據(jù)指針不適合使用,只剩下第三個(gè)數(shù)據(jù)指針可用。DS80C400還具有四個(gè)定時(shí)器。ROM 使用定時(shí)器 0 作為時(shí)鐘周期,使用定時(shí)器 2 作為串行端口輸出。這將計(jì)時(shí)器 1 和計(jì)時(shí)器 3 留給揚(yáng)聲器應(yīng)用程序。
揚(yáng)聲器應(yīng)用使用定時(shí)器3產(chǎn)生中斷,用于加載MAX542數(shù)模轉(zhuǎn)換器。選擇定時(shí)器 3 以在 16 位定時(shí)器模式下運(yùn)行。在 3 位模式下,計(jì)時(shí)器 16 沒有自動(dòng)重新加載,盡管硬件會(huì)自動(dòng)清除中斷位。定時(shí)器3中斷作為高優(yōu)先級運(yùn)行,因?yàn)榧虞dMAX542的時(shí)序?qū)σ纛l質(zhì)量至關(guān)重要。
在應(yīng)用啟動(dòng)之前,ROM已經(jīng)設(shè)置了DS80C400的一些特殊功能。該處理器已經(jīng)處于 24 位尋址模式,允許跨 64kB 邊界輕松訪問代碼和數(shù)據(jù)。擴(kuò)展堆棧也已啟用,利用DS80C400的專用1024字節(jié)堆??臻g。這留下了間接內(nèi)存空間可供應(yīng)用程序使用,而不必?fù)?dān)心堆棧使用會(huì)破壞其內(nèi)容。應(yīng)用啟動(dòng)后,時(shí)鐘四倍器使能,產(chǎn)生約54ns的單周期指令時(shí)間。接下來,初始化定時(shí)器3,這必須在ROM初始化和進(jìn)程交換開始之前完成。這是因?yàn)镽OM在進(jìn)程交換時(shí)保留了中斷啟用位。由于計(jì)時(shí)器中斷需要一直運(yùn)行,因此應(yīng)在啟用進(jìn)程本身之前啟用它。
為了完成系統(tǒng)的初始化,調(diào)用了許多ROM函數(shù)。調(diào)用的第一個(gè) ROM 函數(shù)是 rom_init,它初始化內(nèi)存管理器、進(jìn)程管理器和網(wǎng)絡(luò)堆棧。接下來設(shè)置網(wǎng)絡(luò)參數(shù),為DS80C400提供靜態(tài)IP地址。
系統(tǒng)現(xiàn)已初始化并準(zhǔn)備好創(chuàng)建偵聽套接字。網(wǎng)絡(luò)功能是傳統(tǒng)伯克利式套接字的組裝版本。應(yīng)用程序通過調(diào)用create_socket創(chuàng)建新的 TCP 套接字句柄,并通過調(diào)用bind_socket將其分配給端口號。該函數(shù)setup_listen將套接字設(shè)置為服務(wù)器套接字,accept_connection等待套接字連接。
在程序進(jìn)入主循環(huán)之前,讀取和寫入指針被初始化。傳入數(shù)據(jù)來自 網(wǎng)絡(luò)連接將寫入存儲(chǔ)在間接內(nèi)存區(qū)域中的 EndBuffer 指針,因?yàn)闆]有可免費(fèi)使用且跨進(jìn)程交換安全的直接。第三個(gè)數(shù)據(jù)指針用于從緩沖區(qū)讀取下一個(gè)有效樣本。此指針由計(jì)時(shí)器 3 的中斷服務(wù)例程 (ISR) 獨(dú)占使用。在 ISR 讀取示例數(shù)據(jù)之前,它會(huì)檢查它是否也在讀取 靠近 EndBuffer 指針。如果兩個(gè)指針位于同一組(相同的 64kB 內(nèi)存區(qū)域)中,則計(jì)時(shí)器 ISR 將簡單地退出而不播放音頻數(shù)據(jù)。這不僅可以防止 ISR 讀取緩沖區(qū)末尾以外的無效數(shù)據(jù),但也提供一定量的緩沖,以防應(yīng)用程序接收數(shù)據(jù)的速度不夠快。如果應(yīng)用程序停止播放音頻數(shù)據(jù),則在至少有 64,000 字節(jié)可用之前,它不會(huì)再次啟動(dòng)。這里的權(quán)衡是,如果應(yīng)用程序接收數(shù)據(jù)的速度不夠快,則可以聽到音頻中較長的間隙,但音頻是可識(shí)別的。
循環(huán):等待來自網(wǎng)絡(luò)的數(shù)據(jù)
在應(yīng)用程序的主循環(huán)開始等待數(shù)據(jù)之前,它會(huì)檢查 EndBuffer 指針以查看它是否已環(huán)繞在循環(huán)緩沖區(qū)的末尾,并在必要時(shí)調(diào)整指向循環(huán)緩沖區(qū)開頭的指針。然后,它調(diào)用 recv_data 函數(shù),該函數(shù)讀取任何可用數(shù)據(jù)或塊,直到數(shù)據(jù)可用。接收到的網(wǎng)絡(luò)數(shù)據(jù)直接讀入循環(huán)緩沖區(qū)。這可以防止應(yīng)用程序在recv_data函數(shù)返回后復(fù)制數(shù)據(jù)。如果 EndBuffer 指針靠近循環(huán)緩沖區(qū)的末尾,則 recv_data 函數(shù)僅請求足夠的數(shù)據(jù)到達(dá)緩沖區(qū)的末尾。這意味著應(yīng)用程序有時(shí)可能會(huì)請求接收少量數(shù)據(jù),但好處是應(yīng)用程序可以直接將數(shù)據(jù)讀取到循環(huán)緩沖區(qū)中,而無需中間副本。讀取后,將更新 EndBuffer 指針,控件返回到循環(huán)的頂部。
如果在讀取時(shí)發(fā)生錯(cuò)誤,應(yīng)用程序?qū)㈥P(guān)閉其套接字并等待另一個(gè)套接字連接。通常,檢測到的錯(cuò)誤實(shí)際上意味著主機(jī)關(guān)閉了發(fā)送套接字。這允許發(fā)送方隨時(shí)啟動(dòng)和停止主機(jī)程序,并依次播放多個(gè)WAV文件。
計(jì)時(shí)器中斷:播放音頻數(shù)據(jù)
在執(zhí)行任何任務(wù)之前,計(jì)時(shí)器 3 的中斷服務(wù)例程 (ISR) 必須重新加載計(jì)時(shí)器寄存器。計(jì)時(shí)器寄存器始終以相同的值重新加載。此重新加載值與音頻樣本的播放速率相關(guān)聯(lián)。較高的重新加載值(意味著計(jì)數(shù)器翻轉(zhuǎn)的時(shí)間越短)意味著更快的音頻樣本播放速度。較低的重新加載值意味著音頻樣本播放速度較慢。
重新加載計(jì)時(shí)器寄存器后,ISR 會(huì)檢查它讀取的數(shù)據(jù)是否太靠近 EndBuffer 指針。僅檢查銀行編號(指針的最高字節(jié))有兩個(gè)好處。在前面初始化揚(yáng)聲器應(yīng)用程序一節(jié)中已經(jīng)討論了一個(gè) - 當(dāng)應(yīng)用程序接收數(shù)據(jù)的速度不夠快時(shí),防止出現(xiàn)短而難以理解的音頻突發(fā)。另一個(gè)好處是可以更快地比較 ISR。ISR 每秒運(yùn)行數(shù)千次,因此從 ISR 切割周期非常重要。通過僅檢查高地址字節(jié),可以避免對中間和低地址字節(jié)進(jìn)行兩次額外的比較。
如果有可供播放的有效音頻數(shù)據(jù),則會(huì)讀取樣本,并將數(shù)據(jù)指針遞增到下一個(gè)樣本。數(shù)據(jù)加載到MAX542數(shù)模轉(zhuǎn)換器,首先將片選線設(shè)置為低電平,將2個(gè)字節(jié)加載到串行端口,將片選線設(shè)置為高電平,然后將負(fù)載DAC線脈沖至低電平。串行端口處理串行時(shí)鐘和數(shù)據(jù)線的正確切換。每次加載串行端口后都會(huì)插入幾個(gè)nop指令,允許硬件完成字節(jié)移出。最后,ISR 檢查讀取音頻數(shù)據(jù)的指針,以查看它是否已環(huán)繞在循環(huán)緩沖區(qū)的末尾,并在必要時(shí)進(jìn)行更正。
滴答聲:覆蓋系統(tǒng)計(jì)時(shí)器
為了以允許高質(zhì)量音頻播放的速率接收數(shù)據(jù),需要更改操作系統(tǒng)的計(jì)時(shí)器滴答功能。更改計(jì)時(shí)器時(shí)鐘周期將允許對 I/O 性能進(jìn)行更多控制。以下是DS80C400 ROM中運(yùn)行時(shí)的原始定時(shí)器滴答代碼:
IOPOLL_TICK_MS equ 4 WOS_Tick: ; The timer is running in divide by 12 mode. push psw push acc clr tr0 clr tf0 mov a, sched_reload_lsb add a, tl0 mov tl0, a mov a, sched_reload_msb addc a, th0 mov th0, a setb tr0 inc ms_count_0 mov a, ms_count_0 jnz wos_tick_check_sched ; Check for byte 0 roll. inc ms_count_1 mov a, ms_count_1 jnz wos_tick_check_sched ; Check for byte 1 roll. inc ms_count_2 mov a, ms_count_2 jnz wos_tick_check_sched ; Check for byte 2 roll. inc ms_count_3 mov a, ms_count_3 jnz wos_tick_check_sched ; Check for byte 3 roll. inc ms_count_4 ; If this wraps, we are in trouble wos_tick_check_sched: jb need_sched, wos_tick_check_critical_section mov a, ms_count_0 ; See if it's time to run the anl a, #IOPOLL_TICK_MS-1 ; scheduler/iopoll routines. jnz wos_timer_reload ; If not, don't do scheduler stuff. wos_tick_check_critical_section: clr ea ; Make sure nobody interrupts ; us before we want to mov a, STATUS ; Check for low priority interrupts jb acc.5, wos_tick_low_priority_in_progress ; If low priority interrupts are being ; serviced, don't run the scheduler. ; If we don't do this, we'll start running ; the scheduler as a low priority interrupt. mov a, wos_crit_count ; Check the critical section count. jz wos_tick_not_critical_section ; If we're not in a critical section, ; go ahead, jump and run the scheduler. wos_tick_low_priority_in_progress: setb need_sched ; Signal to ourselves, or whoever, that ; we need to run the scheduler next time sjmp wos_timer_reload ; Going to blow off this tick. wos_tick_not_critical_section: WOS_ENTER_CRITICAL_SECTION pop acc ; Clean up stack. pop psw pop curr_pc_x ; Return address to get out of interrupt. pop curr_pc_h pop curr_pc_l PUSH_DPTR1 push dps mov dps, #0 mov dptr, #WOS_IOPoll ; Get address of IOPoll mov sched_l, dpl mov sched_h, dph mov sched_x, dpx pop dps POP_DPTR1 push sched_l ; Push address of IOPoll push sched_h push sched_x reti ; Run IOPoll wos_timer_reload: ; Interrupts must have been on when the interrupt handler ; was called. setb ea ; Enable interrupts pop acc pop psw reti
此即時(shí)報(bào)價(jià)函數(shù)最重要的更改是使用 1 而不是 4 的IOPOLL_TICK_MS值,并更改sched_reload_xxx值,以便即時(shí)報(bào)價(jià)函數(shù)更頻繁地運(yùn)行。請注意,通過使用IOPOLL_TICK_MS值 1,行anl a,#IOPOLL_TICK_MS-1的計(jì)算結(jié)果始終為 0,從而允許一些代碼和邏輯減少。此外,由于我們不擔(dān)心準(zhǔn)確的系統(tǒng)時(shí)鐘計(jì)時(shí),因此我們可以減少時(shí)鐘重新加載代碼。
一個(gè)復(fù)雜情況是通過覆蓋計(jì)時(shí)器滴答函數(shù)來引入的。揚(yáng)聲器代碼應(yīng)在DS80C400 ROM的任何未來版本上運(yùn)行,因此我們無法對WOS_IOPoll功能的地址進(jìn)行硬編碼。幸運(yùn)的是,WOS_IOPoll函數(shù)的地址在 ROM 導(dǎo)出表中。揚(yáng)聲器程序在啟動(dòng)時(shí)讀取此地址并將其存儲(chǔ)在間接內(nèi)存中,然后由計(jì)時(shí)器 tick 函數(shù)用于調(diào)用 WOS_IOPoll 函數(shù)。以下是針對揚(yáng)聲器應(yīng)用定制的定時(shí)器滴答功能:
speaker_wos_tick: ; The timer is running in divide by 12 mode. push psw push acc ; ; We know what we want our timer reload to be. ; And our millisecond count doesn't have to be too ; accurate, so we can just straight load the ; timer registers. ; mov tl0, #TICK_RELOAD_LOW ; TICK_RELOAD_LOW = 80h mov th0, #TICK_RELOAD_HIGH ; TICK_RELOAD_HIGH = FDh inc ms_count_0 mov a, ms_count_0 jnz wos_tick_check_sched ; Check for byte 0 roll. inc ms_count_1 mov a, ms_count_1 jnz wos_tick_check_sched ; Check for byte 1 roll. inc ms_count_2 mov a, ms_count_2 jnz wos_tick_check_sched ; Check for byte 2 roll. inc ms_count_3 mov a, ms_count_3 jnz wos_tick_check_sched ; Check for byte 3 roll. inc ms_count_4 ; If this wraps, we are in trouble wos_tick_check_sched: clr ea ; Make sure nobody interrupts ; us before we want to mov a, STATUS ; Check for low priority interrupts jb acc.5, wos_tick_low_priority_in_progress ; If low priority interrupts are being ; serviced, don't run the scheduler. ; If we don't do this, we'll start running ; the scheduler as a low priority interrupt. mov a, wos_crit_count ; Check the critical section count. jz wos_tick_not_critical_section ; If we're not in a critical section, go ; ahead, jump and run the scheduler. wos_tick_low_priority_in_progress: setb need_sched ; Signal to ourselves, or whoever, that we ; need to run the scheduler next time sjmp wos_timer_reload ; Going to blow off this tick. wos_tick_not_critical_section: WOS_ENTER_CRITICAL_SECTION mov psw, #0 push r0_b0 mov r0, #wos_iopoll_x mov a, @r0 ; xhigh byte of wos_iopoll address inc r0 mov sched_x, a mov a, @r0 ; high byte of wos_iopoll address inc r0 mov sched_h, a mov a, @r0 ; low byte of wos_iopoll address inc r0 mov sched_l, a pop r0_b0 pop acc ; Clean up stack. pop psw pop curr_pc_x ; Return address to get out of interrupt. pop curr_pc_h pop curr_pc_l push sched_l ; Push address of IOPoll push sched_h push sched_x reti ; Run IOPoll wos_timer_reload: ; Interrupts must have been on when the interrupt handler ; was called. setb ea ; Enable interrupts pop acc pop psw reti
通過實(shí)驗(yàn)測定了FD80h的定時(shí)器重載值。此重新加載值允許以每秒約 88,000 字節(jié)發(fā)送的音頻數(shù)據(jù)流暢播放,中斷最小,具體取決于其他網(wǎng)絡(luò)流量。這意味著以44.1kHz播放單聲道音頻數(shù)據(jù),或以22.05kHz播放立體聲音頻數(shù)據(jù)。
應(yīng)用:構(gòu)建和運(yùn)行
主機(jī)應(yīng)用程序是 Java 應(yīng)用程序,因此需要 Java 開發(fā)工具包來構(gòu)建和運(yùn)行它。在開發(fā)過程中使用了版本 1.3.1,但 SendDataTCP 程序中的代碼非常簡單,任何已發(fā)布的 Java 開發(fā)工具包版本都應(yīng)該足夠了。要構(gòu)建的命令行很簡單:
javac SendDataTCP.java
若要運(yùn)行 SendDataTCP 程序,請使用如下所示的命令行: 在本例中,10.0.0.1 是偵聽端口 80 上的連接的 DS400C5555 的 IP 地址。WAV文件some_song.wav將用于將音頻樣本發(fā)送到DS80C400。請注意,假定使用的WAV文件包含44.1kHz立體聲數(shù)據(jù)樣本。有幾種工具可用于從 MP3 文件生成 WAV 文件。JavaLayer MP3套件中包含一個(gè)免費(fèi)工具
java SendDataTCP 10.0.0.1 5555 some_song.wav
大多數(shù)(但不是全部)MP3 文件都包含 44.1kHz 立體聲數(shù)據(jù),因此請注意任何工具生成的 WAV 文件類型。
在DS80C400上運(yùn)行的揚(yáng)聲器應(yīng)用采用8051匯編編寫,需要TINI軟件開發(fā)套件中免費(fèi)提供的工具5.揚(yáng)聲器應(yīng)用程序是為地址為400000-47FFFF(十六進(jìn)制)具有閃存,在地址00000-7FFFF和60000-67FFFF(十六進(jìn)制)具有RAM的電路板開發(fā)的。圖 4 描述了該板的內(nèi)存配置。
圖4.板內(nèi)存配置。
其他主板的開發(fā)人員需要記住,可能需要更改地址以匹配其主板配置。以下是用于創(chuàng)建揚(yáng)聲器應(yīng)用程序的生成腳本:
macro speaker.a51 a390 -l -Ftbin -d -p 390 speaker.mpp java fixBankNum speaker.tbin 66
工具宏和 a390 是 TINI SDK 的一部分。fixBankNum 程序是一個(gè)小型 Java 應(yīng)用程序,它更改了用于加載應(yīng)用程序的目標(biāo)內(nèi)存庫,并包含在達(dá)拉斯半導(dǎo)體 FTP 站點(diǎn)上本應(yīng)用筆記的源文件中6.請注意,“66”是十進(jìn)制的,因此speaker.tbin文件將針對位于閃存中的銀行 42(十六進(jìn)制)。
fixBankNum程序是必需的,因?yàn)閾P(yáng)聲器應(yīng)用程序不會(huì)耗盡閃存,但將程序存儲(chǔ)在閃存中是確保在DS80C400電源中斷時(shí)不會(huì)擦除程序的唯一方法。揚(yáng)聲器應(yīng)用程序不會(huì)用完閃存,因?yàn)闀r(shí)鐘翻了兩番,它超過了指定的閃存訪問時(shí)間。因此,將運(yùn)行一個(gè)小的初始化應(yīng)用程序,將揚(yáng)聲器應(yīng)用程序從閃存復(fù)制到RAM中。然后,控制跳轉(zhuǎn)到 RAM 中揚(yáng)聲器應(yīng)用程序的副本,然后啟用時(shí)鐘四倍器并開始正常運(yùn)行。此初始化應(yīng)用程序的源稱為 init.a51,也包含在本應(yīng)用筆記的源文件中。使用以下腳本生成初始化應(yīng)用程序:
macro init.a51 a390 -l -Ftbin -d -p 390 init.mpp
要運(yùn)行揚(yáng)聲器應(yīng)用,必須將初始化和揚(yáng)聲器文件加載到DS80C400上。這是使用JavaKit完成的,JavaKit是TINISDK中包含的另一個(gè)應(yīng)用程序。文檔Running_JavaKit.txt(也是 TINI SDK 的一部分)詳細(xì)介紹了如何運(yùn)行 JavaKit。上面的構(gòu)建腳本生成名為speaker.tbin和init.tbin的文件。使用 JavaKit 將這些文件加載到 DS80C400 中。文件應(yīng)加載到庫 41 和 42(十六進(jìn)制)中。要運(yùn)行揚(yáng)聲器應(yīng)用程序,請?jiān)?JavaKit 裝入器提示符處鍵入以下內(nèi)容: 初始化應(yīng)用程序應(yīng)將揚(yáng)聲器應(yīng)用程序復(fù)制到內(nèi)存,打印一些調(diào)試,并且揚(yáng)聲器應(yīng)用程序已啟動(dòng)。運(yùn)行 SendDataTCP 程序以發(fā)送音頻數(shù)據(jù)。經(jīng)過一兩秒鐘的音頻緩沖后,音樂應(yīng)該開始。 B41 X
應(yīng)用:更改程序參數(shù)
揚(yáng)聲器應(yīng)用程序和主機(jī)代碼支持以 44.1kHz、22.05kHz 或 11.025kHz 播放單聲道數(shù)據(jù)。選擇數(shù)據(jù)速率時(shí)要考慮的權(quán)衡是音頻質(zhì)量與網(wǎng)絡(luò)中斷。在低流量網(wǎng)絡(luò)上,應(yīng)用程序可能能夠以 44.1kHz 的頻率播放數(shù)據(jù)而不會(huì)中斷。在高流量網(wǎng)絡(luò)上,音頻中的可聽見的閃光點(diǎn)可能會(huì)變得明顯。請按照以下步驟更改采樣率:
1) | 在文件揚(yáng)聲器頂部附近找到等效RELOAD_44_1_at_18.a51。對于 390.44kHz,將此值更改為 1,對于 800.22kHz,將此值更改為 05,對于 1600.11kHz,將此值更改為 025。 |
2) | 在文件頂部附近找到變量 static int audio_quality SendDataTCP.java。將此值更改為MONO_44100、MONO_22050或MONO_11025。 |
3) | 重新編譯并重建應(yīng)用的兩個(gè)部分,并在DS80C400上重新加載揚(yáng)聲器應(yīng)用。 |
數(shù)據(jù)存儲(chǔ)在音樂光盤上,以立體聲、44.1kHz 16 位樣本形式存儲(chǔ)。單聲道數(shù)據(jù)僅表示播放一個(gè)通道,而不是兩個(gè)通道。音樂的足夠質(zhì)量是22.05kHz;11.025kHz 足以滿足語音數(shù)據(jù)的需求。
揚(yáng)聲器應(yīng)用程序的 IP 地址和參數(shù)也是可配置的。在 speaker.a51 文件底部附近是以下聲明:
network_parameters: db 0, 0, 0 ; 3 bytes overhead db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 1 ; ip address db 255, 255, 0, 0 ; subnet mask db 16 ; ipv4 netmask len db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 2 ; gateway
該結(jié)構(gòu)的格式在DS80C400用戶指南中有描述。但是,請注意,揚(yáng)聲器應(yīng)用程序中使用的當(dāng)前 IP 地址為 10.0.0.1,當(dāng)前網(wǎng)關(guān)設(shè)置為 10.0.0.2。更改以使應(yīng)用程序使用不同的 IP 地址應(yīng)該是微不足道的。在源文件中稍低一點(diǎn),指定了服務(wù)器套接字的端口號:請注意,傳遞給 SendDataTCP 程序的端口號假定為十六進(jìn)制值。
address: db 0, 0, 0 ; overhead db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 1 ; address db 55h, 55h ; port db 0 ; family
未來:添加第二個(gè)頻道和其他改進(jìn)
可以對揚(yáng)聲器應(yīng)用程序進(jìn)行許多改進(jìn)和修改。組播UDP可以取代TCP,允許一臺(tái)服務(wù)器向多個(gè)DS80C400廣播消息。DHCP 可用于動(dòng)態(tài)獲取 IP 地址,從而允許自行配置安裝。配置字節(jié)可能會(huì)告訴揚(yáng)聲器應(yīng)用程序音頻質(zhì)量是多少,因此它可以輕松地動(dòng)態(tài)播放 11kHz、22kHz 或 44kHz 的音頻數(shù)據(jù)。控制從主機(jī)到DS80C400的數(shù)據(jù)流也有待改進(jìn)。
另一個(gè)關(guān)鍵的改進(jìn)是增加了另一個(gè)音頻通道,允許立體聲。這里的訣竅是確保添加另一個(gè)通道不會(huì)使計(jì)時(shí)器 3 中斷例程運(yùn)行太長。最好的解決方案可能是使用串行端口 0 輸出另一個(gè)音頻通道。應(yīng)用程序?qū)⑹ネㄟ^串行端口發(fā)送調(diào)試消息的能力,但計(jì)時(shí)器中斷的額外開銷將降至最低。
結(jié)論
DS80C400 是支持互聯(lián)網(wǎng)的揚(yáng)聲器的完美選擇。DS80C400的ROM使應(yīng)用能夠以傳輸原始音頻數(shù)據(jù)的速度通過網(wǎng)絡(luò)進(jìn)行通信。通過增加一個(gè)16位DAC、一些電阻和少量的焊接工作,DS80C400成為互聯(lián)網(wǎng)揚(yáng)聲器。
審核編輯:郭婷
-
芯片
+關(guān)注
關(guān)注
455文章
50851瀏覽量
423981 -
揚(yáng)聲器
+關(guān)注
關(guān)注
29文章
1304瀏覽量
63053 -
計(jì)時(shí)器
+關(guān)注
關(guān)注
1文章
420瀏覽量
32722
發(fā)布評論請先 登錄
相關(guān)推薦
評論