; MP3 Player, Device Drivers, http://www.pjrc.com/tech/mp3 ; Copyright (c) 2000, PJRC.COM, LLC ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ; Contact: paul@pjrc.com ; where this program will be assembled .equ location, 0x2000 ; where the STA013 config file will be placed .equ sta013_config_location, 0x3000 ; where the MP3 clip is loaded into memory .equ mp3_clip_location, 0x8000 ; This example program is designed to be run with the PAULMON2 ; monitor program. You can easily modify it to be stand-alone, ; These four routines are called to do simple serial I/O... to ; make this into a stand-alone application, just remove these ; four lines and copy the code for these four routines into this ; program. .equ cout, 0x0030 ;Send Acc to serial port .equ cin, 0x0032 ;Get Acc from serial port .equ phex, 0x0034 ;Print Hex value of Acc .equ pstr, 0x0038 ;Print string pointed to by DPTR, ; These lines configure which pins are connected to the STA013. .equ sda_pin, 0x90 ;P1.0 = I2C SDA, Pin 3 .equ scl_pin, 0x91 ;P1.1 = I2C SCL, Pin 4 .equ reset_pin, 0x92 ;P1.2 = RESET, Pin 26 .equ clock_pin, 0x95 ;P1.5 = SCKR, Pin 6 .equ data_pin, 0x96 ;P1.6 = SDI, Pin 5 .equ data_req_pin, 0x97 ;P1.7 = DATA_REQ, Pin 28 ; This little header tells PM2 that this is a program. PM2 ; recognizes these bytes and makes this program appear in ; its run menu. The actual executable code begins at 2040. .org location .db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes .db 35,255,0,0 ;id .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "STA013 Example",0 .org location+0x40 ; begin the STA013 test mov dptr, #msg_begin lcall pstr ;reset the STA013 chip mov dptr, #msg_reset lcall pstr clr reset_pin ;reset the STA013 nop nop nop nop nop nop setb reset_pin ;let it start up ;read the ident register, make sure it's 0xAC mov dptr, #msg_id lcall pstr mov r4, #1 acall sta013_read jc sta013_error mov a, r3 lcall phex cjne r3, #0xAC, sta013_error mov dptr, #mesg_ok lcall pstr ;check to see if the sta013 data file is loaded into memory mov dptr, #msg_ck_cfg lcall pstr mov a, #sta013_config_location >> 8 lcall phex mov a, #sta013_config_location & 255 lcall phex mov dptr, #sta013_config_location acall check_data_file jc sta013_error mov dptr, #mesg_ok lcall pstr ;now attempt to download the config data ;to the STA013 chip mov dptr, #msg_dl_cfg lcall pstr acall sta013_config jc sta013_error mov dptr, #mesg_ok lcall pstr ;tell the STA013 to start running mov dptr, #msg_run_cmd lcall pstr mov r4, #114 mov r3, #1 acall sta013_write ;run command jc sta013_error mov dptr, #mesg_ok lcall pstr ;tell the STA013 to enter play mode mov dptr, #msg_play_cmd lcall pstr mov r4, #19 mov r3, #1 acall sta013_write ;begin play jc sta013_error mov dptr, #mesg_ok lcall pstr ;now let's send it some MP3 data !! mov dptr, #msg_play_clip lcall pstr acall xmit_mp3_clip jc aborted mov dptr, #mesg_ok lcall pstr sjmp quit sta013_error: mov dptr, #msg_error lcall pstr quit: mov dptr, #msg_anykey lcall pstr lcall cin ljmp 0 aborted: mov dptr, #msg_abort lcall pstr sjmp quit xmit_mp3_clip: mov dptr, #mp3_clip_location send_loop: ;we could get stuck here forever if something goes ;wrong with the STA013 and it stops requesting bits jb ri, xmit_abort jnb data_req_pin, send_loop clr a movc a, @a+dptr inc dptr rlc a mov data_pin, c ;send bit 7 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 6 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 5 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 4 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 3 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 2 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 1 setb clock_pin clr clock_pin rlc a mov data_pin, c ;send bit 0 setb clock_pin clr clock_pin mov a, dpl jnz send_loop mov a, dph jnz send_loop clr c ret xmit_abort: setb c ret sta013_config: mov dptr, #sta013_config_location acall get_16_bits ;r6/r7 has cksum addr mov a, r6 anl a, #11111110b mov r6, a cfgloop:acall get_8_bits ;get the address mov r4, a acall get_8_bits ;get the data byte mov r3, a acall sta013_write ;send this byte to its address mov a, r6 cjne a, dpl, cfgloop ;send all the bytes mov a, r7 cjne a, dph, cfgloop ret ;checks for a data file in memory @dptr. The test ;is simple... the first 2 bytes are the location of ;the file's last two bytes, that are a simple 16 bit ;checksum of all the data bytes check_data_file: acall get_16_bits ;r6/r7 has cksum addr clr a mov r0, a ;r0/r1 will hold the computed cksum mov r1, a ckloop: acall get_8_bits ;get each byte add a, r0 ;add it to the cksum mov r0, a clr a addc a, r1 mov r1, a mov a, r6 cjne a, dpl, ckloop ;check all the data bytes mov a, r7 cjne a, dph, ckloop acall get_8_bits ;get cksum lsb mov b, r0 cjne a, b, ckfail acall get_8_bits ;get cksum msb mov b, r1 cjne a, b, ckfail clr c ret ckfail: setb c ret get_8_bits: clr a movc a, @a+dptr inc dptr ret get_16_bits: acall get_8_bits mov r6, a acall get_8_bits mov r7, a ret ;read a byte from the sta013 at address r4 and return it ;in r3. Carry cleared if success, set for fail sta013_read: acall i2c_start mov a, #10000110b acall i2c_write ;wr device addr, wr cmd jc s013r3 mov a, r4 acall i2c_write ;wr addr of data to read jc s013r3 acall i2c_stop acall i2c_start mov a, #10000111b ;wr device addr, rd cmd acall i2c_write jc s013r3 acall i2c_read mov r3, a clr c s013r3: ajmp i2c_stop ;write a byte in r3 to the sta013 at address r4 ;Carry cleared if success, set for fail sta013_write: acall i2c_start mov a, #10000110b acall i2c_write jc s013w3 mov a, r4 acall i2c_write jc s013w3 mov a, r3 acall i2c_write s013w3: ajmp i2c_stop ;i2c stop doesn't change carry bit i2c_write: ;writes acc to i2c bus, return ack bit in Carry mov r5, #8 i2cw: rlc a mov sda_pin, c nop nop setb scl_pin nop nop clr scl_pin djnz r5, i2cw rlc a setb sda_pin nop nop setb scl_pin nop nop mov c, sda_pin clr scl_pin ret i2c_read: ;reads i2c bus into acc, send ack bit from Carry rlc a mov r5, #8 setb sda_pin i2cr: nop nop setb scl_pin nop nop mov c, sda_pin rlc a clr scl_pin djnz r5, i2cr mov sda_pin, c nop nop setb scl_pin nop nop clr scl_pin ret i2c_start: setb sda_pin setb scl_pin nop nop clr sda_pin nop nop clr scl_pin ret i2c_stop: clr sda_pin nop nop setb scl_pin nop nop setb sda_pin ret msg_begin: .db "STA013 MP3 Decoder Test Program",13,10,0 msg_reset: .db "Reseting STA013",13,10,0 msg_id: .db "Reading IDENT register: ",0 msg_ck_cfg: .db "Checking p02_0609 (config data) at 0x",0 msg_dl_cfg: .db "Downloading Config Data to STA013 chip:",0 msg_run_cmd: .db "Sending RUN Command: ",0 msg_play_cmd: .db "Sending PLAY Command: ",0 msg_play_clip: .db "Playing MP3 Clip From Memory: ",0 msg_anykey: .db 13,10,"Press any key to restart: ",0 mesg_ok: .db " Ok", 13, 10, 0 msg_error: .db " Error",13,10,0 msg_abort: .db " Abort",13,10,0