Friday 12 June 2015

vwcdpic for avr (arduino) and attiny


Porting to arduino's or AVR?

I sell on Tindie
while back I read on hackaday forums about guy who ported some C code for avr (for seeduino mega) originaly ported from k9spud vwcdpic ...

back then I was really bad in arduinos or any coding for mcus, so I was unable to make it work on normal *duino .... 

then i find this post of shyd version of emulator 

and now i'm less lame so I did it :)

Problem


for protocol read shyd post, it preaty explain everything about pulses etc ....

problem of porting avr vwcdpic code to arduino:

- ICP pin need to be accesible
- one 16bit timer (attiny hase 2x8bit timer)
- two timers with CTC (atmega8 does not have ctc)

ICP pin


basicaly external logical change interupt on pin called ICP which is directly "wired" to timer1( ICP as INPUT CAPTURE PIN), this pin is not wired on ATMEGA arduino boards (mega1280 and 2560). This is why guy on hackaday use seeduino...
On normal arduino duemilanove or UNO is ICP1 on digital pin 8, so this will work perfectly on duemilanove/uno and also old atmega8 chips.

Also its posible to reprogram code to use standard INTx interupr as I use in attinyx5 version of this code.

16bit timer

this timer is used to measuring pulses length of data send by head unit, more in post here and here.

In original code is set to tick every 0.5us, its 16bit timer, max value of 65536 which corespod to 32000something ms ~ 32second, which is fine, perfect resolution, we can surely set input buffer to zero if this timer overflow (no logical change on ICP pin for 32 seconds...)

but if we have 8bit timer like in attiny85 (255tics to overflow which is 128us if I'm not mistaken) and want to have same resolution as with 16bit timer, to avoid recalculation of tics per pulse.... we must catch overflows and count them, then just calculate pulse lenght as 255*overflows+actual timer

2 timers for timing output packets

next challenge was timing for output to head unit, lets call it packet of 8 bytes, with this timing:

50ms between pakets
at last 700us between bytes in packets (in vwcdpic is note that same head units cant store it if timing was 350us, in some other sources on net, timing is 874us ... but 700us works for me...)

in original code timer0 and timer2 are 8bit timers, in original code used for:

- 700us timing between bytes
- 50ms timing between packets and to cound seconds ... (20x50ms = 1000ms = 1s)

this is no problem on atmega168/328 but its problem on atmega8 and attiny85

atmega8 has no compare register for timer0, attiny85 hase just two 8bit timers/counters

Timer0 on atmega8


atmega has timer0 without CTC mode, no compare possible , so we must make it work other way around, we have overflow:
-  so I set OVF bit to allow execution of OVF runtime routine
- set timer to 4us tics, this make it overflow each 1024us
- initialize timer with value of 6 which make it overflow after 1000us
- in overflow routine  timer is initialize with 6 to overflow again after 1000us



Attiny85 and two 8-bit timers


timer1 is used for input capture with combination on int0 external interrupt and counting overflows... no big deal

timer0 must be used to timing of 1ms tics for seconds count and for output packets timing, so what I did was really easy, and I go to rewrite all code also for atmegax chips to use it. I set timer to tic every 1us, set compare register to be 100, so its fire compare routine every 100us. In this routine I do counting, 50 count to make original code happy ...
and to count to 7 or to 50 to make output packets timing work ...

second timing for output packets is set directly in code which handle sending packet, if it reach end, it will set 50 to wait 50ms between packets, if it just sent less then eirhts byte it set 7, so next byte is flush out after 7 overflows of timer0 = 700us

Output to headunit

output to head-unit is SPI, it's nothing new, but this didn't work for 16Mhz arduinos (simply it's to fast), so software handling of this is used. I like crystal version more over internal RC oscillators becose this is in car application where external crystal should by better, but I do not test or read any paper on this, so correct me please if I'm wrong.

also attiny has no SPI dedicated pins, it it's capable of use some internal magic to have SPI by HW but it use pin which is also INT0, and this we need... so using software here is only option

Serial comunication


Original vwcdpic used 9600bauds serial communication for PJRC player, which I do not know if it is around anymore, but it was also in avr code, so I leave it there just make it fully backward compatible, with "in compile time" configurable #define PJRC, becose this make emulator constantly send "mode" on serial line, which may toggle  "mode" on mpd  each second or so ...

also add option to support shyd version of serial communicaton to control mpd over serial with mpc and python, and receive info from mpd like mode, disc and track number. This is configurable in compile time with  uncommenting #define DISC_TRACK_NUMBER_FROM_MPD, #define JUST_HEX_TO_SERIAL and commenting out #define PJRC

attiny85 use TinyDebugSerial library which is oneway library but it didn't use any timer, so I can use both(timers).

 Mpd control

I made some changes of shyd python script to control mpd both with just hex and pjrc commands , this are on github. Also mpd_control_vwcdpic.py should support original pic version of vwcdpic, but I have no time to check it.

I make this pythons script handle next/previos CD which are send (as I know) only from audi chorus 1 with enabled CD input and audi concert 1.

video of all of this is here:


how to wire it?

arduino duemilanove/uno or atmega8
RADIO PIN -> arduino pin (chip pin) <- computer
     DataOut -> digital 8      (14)
       DataIn -> digital 13    (19)
         Clock -> digital 12    (18)
                        digital 0      (2)  <------------ serial TX
                        digital 1      (3)  <------------ serial Rx
 
attiny85:
RADIO PIN -> attiny pin <- computer
     DataOut -> 7
       DataIn -> 6
         Clock -> 5
                        2  <------------- serial RX

Future

 Bluetooth... clearly, I made it here, with blk-md-spk-b module, but it has problem handling calls, so I ordered xs3868 and made kicad module and library. So next to make some breakout boards and try it.

 Next stage is implementing SOYO-BT24G03 (made kicad library, module, get AT command set ) which has support of more profiles (also address book ;) ) and also has support of sdcard and usb :) 

BM20 it will be ;)

Links 

arduino,atmegaX8,atmega8 port of  k9spud vwcdpic
port of k9spud vwcdpic with two 8-bit timers (attiny85)
mpd_control.py
mpd_control_vwcdpic.py 
 

15 comments:

  1. Hello,
    I didn't find serial rx and tx on rcd 300. please tell me what pins are rx and tx. thank you

    ReplyDelete
  2. Hi. Can not compile your latest sorce code cdc_arduino_ported_k9spud_vwcdpic with for my arduino nano v3. Please help.

    ReplyDelete
    Replies
    1. compile fine on my arduin. did you download functions.ino into same directory as cdc_arduino_ported_k9spud_vwcdpic.ino ?

      log:http://pastebin.com/SXKSmsZ0

      Delete
  3. Magaed to compile. Thank you Thomas. Now I am experiencing problem with running python script. Unlike original script yours is playing MPD playlists. Do I have to manually create them? I have created playlists manually CD1, CD2, CD3..etc. Do I need to enter value into last_cd file? Now when I run python2 mpd_control.py from MoOde raspberry distro it gives me:
    stoped
    not playing[1]
    no playing [3]
    not playing[1]
    no playing [3]
    Any ideas?

    ReplyDelete
  4. look here, they should be named cd in lowercase

    http://dev.shyd.de/2013/09/avr-raspberry-pi-vw-beta-vag-cdc-faker/

    t.

    ReplyDelete
  5. Renamed CDs to cds. created playlists cd1.m3u, cd2.m3u..This did not help. Same error when connected to Rpi.

    ReplyDelete
    Replies
    1. Idid.playlist in gmpc, so i do not know .... Is it evet workplaylist you created) in mpc?

      Delete
  6. Ooops. I forget to uncomment #define JUST_HEX_TO_SERIAL for mpd control.:(

    ReplyDelete
  7. Hmm. This did not help. Noticed weird thing. When python script first run, CDC changer disconnects and radio says no changer. Same happens if I run python->import serial->ser = serial.Serial('/dev/ttyUSB0', 9600) radio shows no changer. And I need to press cd to change to CDC. I have tested serial connection with simple sketches. Can read and write to/from Adruino. I have Arduino Nano v3 with CH340G chip. Connected to Audi Concet CD. Any more ideas?

    ReplyDelete
  8. Здравствуйте . А можно написать скеч эмулятора для Ардуино Уно?

    ReplyDelete
  9. hi, my only problem is when I long press [>/<] (next/prev CD), the radio keep sending command Do_SEEKFORWARD/Do_SEEKBACK. my board is arduino uno, radio is RCD200. should I respond with a state change? thank you, excellent work, even after so much time!

    ReplyDelete
  10. Hello.. Just doing CDC faker with arduino nano and stick BTaudio to with it, is there code out there for it?

    ReplyDelete