Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : (MM) D/A converter
Page 2 of 3 | |||||
Author | Message | ||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
Well, it does what it does. :) I think the real challenge comes later when the SPI is used. Not that sending data to the SPI will be difficult but the timing. The timing if it is critical will change everything. And indeed the lot more work is in that. I like KISS but if i was in teaching mode i would give this code a very low grade. :) Using EOF is in my opinion so easy to use that not using it is a shame. Code should be as error free as possible and EOF will prevent an error to occur. This will be very useful when it is time to expand on your program as it will prevent new and unexpected behavior. I don't know what is the most interesting part for you when using MCU's. I get the most fun out of making code that is as small as possible and as robust as possible. I go through great lengths, like pulling out cables, inputting text when numbers are expected, pressing all the wrong buttons etc to get the software to crash. For that reason i concentrate the most on software and it is also the reason for responding to your post as it is more about software then hardware. If however you get the most joy out of hardware, soldering, interfacing etc and software is just a necessity, then you probably want to do the job in software as quickly as possible and not worry about best practices and robustness. In that case ignore the above and have fun, because that is the most important. If timing is important you can check how close you are to the target by using the TIMER command and function. Firsdt you use TIMER = 0 to reset it. Then after a specific number print the timer value on the screen. If you want to have 50 per second you could use a counter variable to keep track of how many times the code in the loop has run. You should get timer value 1000 when it exactly 20ms per message but in practice it will deviate. If you want to do that you will need to add a variable before the DO statement: Count = 0 TIMER = 0 then right after the PAUSE 20 statement: Count = Count + 1 If Count >= 50 then Count = 0 Print Timer Timer = 0 end if I am curious what kind of values you will get and how close to the 1000 they are. Microblocks. Build with logic. |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Thanks Jean, And thanks for your continued input. I'm not the world's best programmer ("a very low grade" is acceptable!) so taking things in small bits is the best way for me. Input from forum members has been a real lifesaver. I did BASIC at tech 100 years ago and haven't done much since although I did cut my teeth on the RCA 1802 chip. We made some data loggers for a research project. It had 16 X 16 bit registers and you needed every one of them! So working at bit level is what I like best. The MM has me inspired again. You've probably seen my other posts on my clock. I started it to get others to get stuck into me and come up with something better. No one has yet. This Apollo 11 data is something I'm just dabbling with. According to my rough calculations, the amount of data that I have amounts to about 13 hours of the first moonwalk. Don't worry. I've followed everyone's comments on the EOF and the timing. I just want to get it going first and then refine things later. I will go through each data item on the PC and tidy it up by making sure that each item is valid and is not a random number. In fact there are a lot of those. There are data dropouts, random numbers and what would be described as glitches in the data. It's not surprising. After all, the data did come all the way from the moon, through God only knows what path. Then when I'm happy I'll copy it onto the SD card. Then I'll add error catching in my program to check each item as it's read off the SD card, then SPI it. I'll probably replace it with the number that was previous to the error. If I don't do this then the Helicorder pen will show a twitch or at worse slam to the side for a brief moment. When I say that timing is critical in seismic work - it's important that each seismic station is locked into UTC. Some scientists insist on uSec accuracy. But for this project it's not all that important. A few mSec either way is not an issue. I just need to make sure that at the end on the 13 hours I'm not minutes out. I have the original seismogram to test it by. It has the Helicorder time marks on it. The digital data is time tagged but Yosio warned that it can't be relied on because of the way it was resurrected. In fact I can see that there are say 10 readings in a group then there might be 11 or 9. But I'll take your advice and check the timing. If I wanted to be really accurate I could use the PPS from a GPS. Over a 13 hour period it in fact might be essential! I wish these damn boards would arrive. Anyway, please keep the advice coming. Trevor Talbit |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
A PPS is i think not necessary to be accurate. MMBasic has a timer interrupt that is accurate within 0.1ms. I think that is all that is necessary, if testing shows that this timer interrupt is not really accurate you can use one of the PWM pins to generate the 20ms pulses. Those will be generated by the internal PIC32 peripheral and are very accurate. By connecting a PWM pin output to another pin for input you can use the interrupt of that input pin to provide very accurate timing to the MMBasic program. Response time is again around 0.1ms because that is the time for the basic interpreter to process that interrupt. The next pulse will be exactly 20ms later, effectively removing the possible timing inaccuracy of MMBasic. The routine that handles the interrupt has to be shorter then 20ms, more like 15ms to prevent missing a 20ms pulse. Microblocks. Build with logic. |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Using the counter and the timer it works out to 1001/1002 milliseconds per 50 samples, with a pause of 18. A quick calculation says that after 13 hours I'll be about 46 seconds out. OPEN "ApolloAS.txt" FOR INPUT AS #1 Count = 0 TIMER = 0 x = 0 DO LINE INPUT #1, values$ PRINT values$ Pin(14)=0 a = SPI(12,13,15,val(values$),H,3,12) Pin(14)=1 PAUSE 18 Count = Count + 1 If Count >= 50 then Count = 0 Print " "Timer x = x+1 Print " "x Timer = 0 Endif LOOP I've also got a software counter that gives me a count every 50 samples, i.e once a second. I'm up to about 1.7 hours and it is running okay. BTW, I've reverted to the three original characters ascii data which hovers around 530. I need to add the control bits to this to make up the 16 bit binary word for the SPI. Tomorrow I'll connect a cro and see if there is anything actually beng sent from the SPI tx pin. Trevor Talbit |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
That is a pretty good result! 1001/1002 is perfect. The next thing you could test for is exceptions. If Count >= 50 then Count = 0 if Timer > 1005 then x = x+1 print " "Timer" "x Timer = 0 end if end if If you run it with this it will only print when the time spend in the loop is too long. Change the value 1005 for a maximum value that the timing is allowed to drift. Reading speed from files on the SD can vary. This can cause (worst case) delays of a few seconds. When that happens the timing is completely off and another way of processing have to be made.. Running the above for the whole file will detect when the processing is too slow. If you process the whole file and no timing drifting is detected in trial runs then you are good to go. Microblocks. Build with logic. |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Okay, almost there! Can anyone help me with this? It's probably mentioned somewhere down in the archives but this is related to my project. It's binary arithmetic so I know someone will answer straight away! The SPI command sends the MSB first. See Appendix D The data for the SPI chip on the Futurlec DAC board (Microchip MCP4922) says it wants the LSB first. So, say my 16 bit binary number is (LSB)0100110001101110(MSB), how do I turn it around so I get 0111011000110010 The DAC boards from Futurlec still haven't arrived. I contacted them and they said they have just been posted. Yeah Right! I think they forgot. Regards Trevor Talbit |
||||
ajkw Senior Member Joined: 29/06/2011 Location: AustraliaPosts: 290 |
there may be a better way but try byte = 19566 ' sample 0100110001101110 for i = 15 to 0 step -1 newbyte = newbyte + ((2^(15-i)) * ((byte AND (2 ^ i)) > 0)) next i print newbyte ' Should return 30258 being 0111011000110010 In other words, test the MSB and set it in a new var as the LSB and step thru. QED. Sample code only, make sure you do your own error testing and that it suits your purpose! |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
Talbit, The datasheet from the MCP4922 clearly shows that the data is to be send MSB first! Look on page 7 and 25 from this datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22250A.pdf Where did you find the information that it should be LSB? Microblocks. Build with logic. |
||||
ajkw Senior Member Joined: 29/06/2011 Location: AustraliaPosts: 290 |
Refer my previous post in this thread. Thanks to crackerjack for the bit test in the BIN8.bas code in the sample library. A better test than I had done in the past. There are also a number of other bit manipulation functions in BIN8.bas |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
Talbit, I just noticed this in your post: (LSB)0100110001101110(MSB) The LSB and MSB should be switched like this as it is the normal practice and how values are stored in memory: (MSB)0100110001101110(LSB) The bits are D15, D14, D14 ....... D3, D2, D1, D0 It works the same as with our normal decimal system: 123 Here the 1 is Most Significant as it stands for 100, and the 3 Least Significant. Microblocks. Build with logic. |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Gents, This would have to be the most embarrassing day of my life! You're absolutely right. The MSB is first. The data sheet even shows the 1st. clock "0" associated with D15, the MSB. My blunder. Thanks anyway to ajkw for the interesting number crunch on how to turn it around. Jean, I was trying to indicate that the MSB would normally come first hence I put it to the right. Not good! So my data should be D15, D14, D13 ....... D3, D2, D1, D0 0111011000110010 The 0111 are the control bits and the rest is the data. I was working off a 2004 data sheet (DS21897A). I don't know where it came from. Probably a link on the Futurlec site. But it's no excuse. Thanks for pointing me to the newer data. It shows a bit more than the older sheet. Thanks again. Trevor ps I won't post my final code until I get it working. Trevor Talbit |
||||
James_From_Canb Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
Just in case anyone wants to swap two bytes in a 16 bit word, here's some code. It shows how useful the AND and OR functions are for manipulating bits. This'll be old news to experienced programmers, but there might be some of you out there who are interested. James ' Example code to swap two 8 bit bytes in a 16 bit word. byte = 19566 ' sample 0100 1100 0110 1110 print "Start word is " bin$(byte) ' First, split the 16 bit word into two 8 bit bytes, Left byte and a Right byte. ' Use the AND function to extract the bits we want. They're already on the RHS of the word. ByteR = byte AND &b0000000011111111 ' should return 110 decimal being 0000 0000 0110 1110 print "Right byte is " bin$(ByteR) ' Then extract the leftmost 8 bits using an AND mask and SHIFT the bits to move them to the RHS ByteL = byte AND &b1111111100000000 ' should return 0100 1100 0000 0000 ByteL = ByteL / &b100000000 ' shift right by 8 bits. Should return 76 decimal being 0000 0000 0100 1100 print "Left byte is " bin$(ByteL) 'Now swap the two bytes. The original Left byte has already been moved to the right of the 16 bit word. Leave it there. newbyte = ByteL ' newbyte should be 0000 0000 0100 1100 'The original Right byte has to be moved left. Do this by shifting left 8 times (multiply by 2^8, or 128) TempByte = ByteR * &b100000000 ' Should return 28,160 decimal being 0110 1110 0000 0000 print "Temp Byte is " bin$(TempByte) ' now merge the two bytes back together again using the OR function newbyte = newbyte OR TempByte ' Should return 28,236 decimal being 0110 1110 0100 1100 print "New word is " bin$(newbyte) print "The two bytes have been swapped." My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Thanks James. I could use that on other projects later. I'm wondering if it might be useful to start a thread on this subject. Someone might have already started one but it might have disappeared into the ether if people don't keep adding to it and keeping it active. For now, I have a question on how the picking of the data off the SD card works. My code is this and it works perfectly... 'Simplified code. The data is on the SD card. OPEN "Apollo.txt" for INPUT AS #1 DO LINE INPUT #1, values$ 'Get the first DATA from the SD card 'Crunch the numbers. LOOP 'Go and get the next DATA from the SD card My question is, how does it know to get the next line of data. Is the #1 a pointer that increments? I like to know exactly what’s going on so I don't come unstuck later if I assume too much! Regards Trevor Talbit |
||||
James_From_Canb Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
When you open a file MMBasic will set up some data fields to manage it. You don't get access to the fields directly. One of those management fields will be a pointer that keeps track of the next byte to be read from the file. The number after the hash doesn't increment as you read through a file. If it did, you'd be pointing to the next file you have open (assuming you open your files using sequential numbers). #1 is just a string telling MMBasic that we're using a particular file and that the associated file management fields should be used. When you tell MMBasic to do a Line Input, MMBasic reads all the bytes from the next pointer up to the End of Line characters. The next pointer is then changed to point to the byte after the EOL character/s. The question everyone asks sooner or later is how the program knows when the End Of File (EOF) has been reached. If MMBasic has only read bytes preceding the read pointer (which points to the next byte to be read) then how can it know that the last byte in the file has been read? That's up to the Geoff, but probably involved reading a byte ahead to check for the EOF character, while not changing the read pointer. It doesn't really matter how it's implemented. Just trust that it works. Except in one case... MMBasic only handles text files so far. It doesn't handle binary files. If you're reading a binary file using MMBasic's text file functions you can have your read terminated by an EOF character. Binary files are likely to have data bytes with a value of 26 which is interpreted by MMBasic as an EOF character. This stops the entire file being processed. I hope that made some sense. Ask if it didn't. You should get an error when your code (above) tries to read past the End of File. You need to use the EOF() function. Geoff's manual says EOF(#nbr) "Will return true if the file previously opened for INPUT with the file number "nbr" is positioned at the end of the file" so try replacing the DO with DO While NOT EOF(1). HTH James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
James, That all makes sense. Thanks for the input. My numbers on the SD card aren't HEX like at the beginning of this thread. They are just 3 digit numbers. I do a bit of bit bashing to get what I want. I'll post it all when it's all working (to save embarrasment). I have inserted my own EOF. I've just inserted the number 1050 at the end of the 11.5MBYTE file and check for it each line read. All of my numbers are less than 1050 so it doesn't exit early. When it reaches 1050 it exits the SD card read routine and stops. It seems to work okay. Chrickey Futurlec are slow! I wanted to get this finished before I went back to work on Monday. Regards Trevor Talbit |
||||
paceman Guru Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
I was thinking the same thing Trevor. This info re binary manipulation, MSB/LSB transmitting and file reading is very good info for we "ordinary" folk Unfortunately it'll be difficult to find later under a thread on D/A converters! Maybe Glenn could put it in a separate thread under "SPI bit transmission & file reading" or some such. A good start point would be your post (Talbit) just after 4pm on the 16th Jan. I've already copied James' little swapping program/info into a folder I keep for useful MMBasic stuff. Greg |
||||
James_From_Canb Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
I agree with the idea. You don't need Glenn to solve it though. There's nothing stopping you cutting and pasting the relevant information into a single post and starting a new thread with an appropriate title. Even better, as new threads expand on the subject people could update/improve the summary. If you do, I'd suggest that you preface the thread's title with SUMMARY: so that users can use the search facility and only search for the threads with SUMMARY in the title. The default is to search for the keywords in the message body, so a search for SUMMARY would find this posting. Just a thought. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Some sort of index is needed. The forum does have search facilities, but you got to know what your searching for. But an index of topics, like A-D conversion, File handling, etc, and under each topic a few links to relevant posts. If someone where to put together and manage the index, I would be happy to put it on the forum as a sticky, so its always at the top. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
paceman Guru Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
I had a quick look at the forum "Search" functions using "summary" as the input. If you select to search on the body of the posts you get too many hits. Also it's difficult to know what the "found" posts are about, so you have to look at each in turn which is too time consuming. If you select to search on the titles there are currently no hits at all. I think a combination is needed. If Glenn put a "sticky" post at the top of the forum which said to search for "summary" in the "titles" area (not the default body area) for information on particular subjects, then a manageable list of "Summary" threads would come up (currently there wouldn't be any!). The sticky should then say to search the body of the most likely summary thread, using the keyword(s) of interest. A few lines of suggested keywords could be included in the "sticky" which would be easy to update. what do you think? Greg |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
The DAC boards from Futurlec finally arrived and it works beautifully. The Apollo 11 moonwalk seismic is being faithfully reproduced on a Teledyne Geotech Helicorder. The whole data set should last about 14 hours. Further work needs to be done to get the time marks in the exact spot to match the original recorded on the day of the big event in 1969 When I've completed a full run I'll try and take a happy snap of the setup, the seismogram and the circuit. The circuit is pretty straight forward. Here's the code. All pretty straight forward when you know what to do! Thanks to all who contributed with advise and suggestions. Whoops - In the code where it says 'Add DAC control bits (0111) resulting... that should read 0001 'Apollo 11 First Lunar Seismogram, July 1969
'Original data supplied by Yosio Nakamura Institute for Geophysics 'University of Texas at Austin [yosio@utig.ig.utexas.edu] 'Stored on Maximite SD card 'Trevor Dalziell 26 January 2013 ' 'Data to the Futurlec SPI DAC board (Microchip MCP4922) is 16 bit 'straight binary. 'Only 1 of the DAC amplifiers is used 'Bits 0-11 are data from the Maximite. 'Bit 12 is Output Power Down Control bit (active low). Set to 1 'Bit 13 is Output Gain Select bit. Set to 0. Gain of 2. 'Bit 14 Vref Input Buffer Control. Set to 0. External Vref. 'Bit 15 selects which DAC to write to. Set to 0. Writes to DAC "A" 'This relates to the upper four bits as 0001 '____ SPI Setup ____ Pin(14) = 1 'Pin 14 is High Pin(15) = 1 'Pin 15 is High Pin(16) = 1 'Pin 16 is High Setpin 12,2 'Digital input - Data Rx (Ignored) Setpin 13,8 'Digital output - Data Tx Setpin 14,8 'Digital output - DAC Chip Enable - Active low Setpin 15,8 'Digital output - Clock - Active low Setpin 16,8 'Digital output - LDAC - Active low OPEN "Apollo.txt" FOR INPUT AS #1 'This file should have 1050 'as the last data entry (EOF) DO LINE INPUT #1, values$ 'Get the first number from the SD card a = VAL(values$) IF a = 1050 THEN '1050 = EOF EXIT 'Exit out of loop if EOF ENDIF 'Not EOF so continue Seismic = a AND &B111111111111 'Mask the data to prevent overflow Seismic = Seismic OR &B0001000000000000 'Add DAC control bits (0111) resulting 'in a 16 bit word 'Now send the data via SPI PIN(14)=0 'Enable DAC s = SPI(12,13,15,Seismic,H,3,16) 'High speed, Mode 3, 16 bit control and data. PIN(14)=1 'Disable DAC Pin(16)=0 'Latch the data Pin(16)=1 PAUSE 20 'Wait for 20 msec LOOP 'Go back and get the next number CLOSE #1 'EOF found so stop reading the SD card data 'Now just output a voltage that will keep the pen centred '&B001000010010 Helicorder pen centre position? PIN(14)=0 s = SPI(12,13,15,&B0001001000010010,H,3,16) 'High speed, Mode 3, 16 bit Control and Data. PIN(14)=1 Pin(16)=0 'Latch the data PAUSE 1 Pin(16)=1 END Talbit |
||||
Page 2 of 3 |
Print this page |