Hi,
Following is my proposal for a platform interface for the ADC peripheral. I have only very limited experience with ADCs/DACs, in fact the only two "serious" applications that I wrote and used ADCs were based on external components and were quite basic on the data acquisition part, so you might find this specification incomplete or just plain strange. If so, please let me know so we can refine it to a better form. I tried to extract a common set of features of ADCs from all the CPUs that eLua currently supports, and this is what I came up with: - most (or maybe all) of them support both "single shot" and "continous" modes - some of them let the user select ADC timings (like startup time and sample&hold time). This seems to be quite rare though, so I won't include it in the platform interface. - some of them also support a special mode in which they are "paired" with a hardware timer and use that timer as a conversion clock. This is useful, and it can be emulated even on platforms that don't support this feature. With this in mind, this is what I came up with: int platform_adc_exists( unsigned id ); // generic, it will be part of src/common.c u16 platform_adc_sample( unsigned id ); // sample the specified ADC channel void platform_adc_start( unsigned id ); // starts a conversion on the specified ADC channel and returns immediately int platform_adc_is_done( unsigned id ); // returns 1 if the conversion on the specified channel ended, 0 otherwise void platform_adc_set_mode( unsigned id, int mode ); // sets the mode on the specified ADC channel to either "single shot" or "continuous" void platform_adc_burst( unsigned id, u16* buf, unsigned count, u32 frequency ); // burst conversion: read "count" samples from the ADC channel "id", storing the results in "buf". The samples are read at periodic intervals, the period is given by "frequency". That's about it for now. What do you think? Best, Bogdan -------------- next part -------------- An HTML attachment was scrubbed... URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090108/5205151c/attachment.html |
Overall, those make a good core for the ADC functions. I think a few
additions might be nice as well. On Jan 8, 2009, at 3:07 PM, Bogdan Marinescu wrote: > Hi, > > Following is my proposal for a platform interface for the ADC > peripheral. I have only very limited experience with ADCs/DACs, in > fact the only two "serious" applications that I wrote and used ADCs > were based on external components and were quite basic on the data > acquisition part, so you might find this specification incomplete or > just plain strange. If so, please let me know so we can refine it to > a better form. > I tried to extract a common set of features of ADCs from all the > CPUs that eLua currently supports, and this is what I came up with: > > - most (or maybe all) of them support both "single shot" and > "continous" modes > - some of them let the user select ADC timings (like startup time > and sample&hold time). This seems to be quite rare though, so I > won't include it in the platform interface. > - some of them also support a special mode in which they are > "paired" with a hardware timer and use that timer as a conversion > clock. This is useful, and it can be emulated even on platforms that > don't support this feature. I agree with the use of the timer as a conversion clock. In a related vein, one thing that I've not used on micros that much, but have on dedicated ADC boards is the use of triggers for sampling. This would be particularly useful for burst sampling. Sometimes this is done based on the signal itself, but often with a digital trigger. The digital trigger should be pretty easy to do by having the kickoff be interrupt driven. If a board doesn't support external interrupts, you could always emulate it by polling, although it's not as good. I guess this brings up the question: do we allow arbitrary pin selection regardless of whether it will generate interrupts? I have less knowledge of how this is supported on various 32-bit platforms that eLua is running on. IIRC, the LM3S boards can do interrupts on any pin. > With this in mind, this is what I came up with: > > int platform_adc_exists( unsigned id ); // generic, it will be part > of src/common.c > u16 platform_adc_sample( unsigned id ); // sample the specified ADC > channel OK. So this will return the latest sample collected? Does it block waiting for completion if the latest one hasn't finished yet? Also, should this behavior be different in continuous vs single shot? i.e.: Single Shot: wait for sample if not ready Continuous: take whatever the last completed sample was? wait for next sample? (I think the former would make more sense as a reason to use continuous sampling). > void platform_adc_start( unsigned id ); // starts a conversion on > the specified ADC channel and returns immediately > int platform_adc_is_done( unsigned id ); // returns 1 if the > conversion on the specified channel ended, 0 otherwise I wonder if in the case of using an interpreted language like Lua that one might be converting values fast enough that having some sort of loop waiting for the data to be done might not be fruitful, at least in single shot mode? Certainly, one is more likely to need this if one wants to know if a burst has completed. > void platform_adc_set_mode( unsigned id, int mode ); // sets the > mode on the specified ADC channel to either "single shot" or > "continuous" Hmm.. what about adding a filtered/smoothed mode? By this I don't mean anything particularly intense, perhaps just a ring buffer of a set length that gets averaged whenever platform_adc_sample is called. I find myself frequently doing things like this when sampling things that are noisier than the best resolution the ADC can deliver. My only thought here would be that the C code might do this faster than doing the averaging in Lua. One way to handle this somewhat elegantly would be to not even add anything to the mode function, just have the default buffer be of length 1, and under this condition, no smoothing is done. If you want it, use the following function to enable the rolling average: void platform_adc_set_smoothing( unsigned id, int length ); // sets window length/buffer size for moving average filter Does this seem too much to have in the library? > > void platform_adc_burst( unsigned id, u16* buf, unsigned count, u32 > frequency ); // burst conversion: read "count" samples from the ADC > channel "id", storing the results in "buf". The samples are read at > periodic intervals, the period is given by "frequency". I like this as well. One thing that might be interesting to provide as well, would be some method to do this type of recording directly to a binary file in the mini filesystem or onto an SD card or something similar. This could be useful if one wants to capture more data than can be held in SRAM at once, but the sampling rate would have to drop down to much to record and transfer data a machine connected to the micro. I realize some of these things might extend beyond what could be appropriate for a simple module, but I think they could be useful just the same. Also, I think the original functions make sense to get working as an initial implementation before making any of the extensions I'm proposing. Thoughts? -- James Snyder Biomedical Engineering Northwestern University jbsnyder at fanplastic.org http://fanplastic.org/key.txt ph: (847) 644-2322 -------------- next part -------------- An HTML attachment was scrubbed... URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090109/1e66edac/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 194 bytes Desc: This is a digitally signed message part Url : https://lists.berlios.de/pipermail/elua-dev/attachments/20090109/1e66edac/attachment-0001.pgp |
Bogdan, any thoughts on these points?
I'm a little busy at the moment (work pileup, plus a not quite cheap linear actuator broke on a project of mine.. AC servos can pack quite a punch), but I'm going to resume work on this in a day or two. My reasoning on including the filtering/smoothing is that doing averaging and data handling in C might be lighter weight than having them converted to tables and then iterating in Lua, but I could be wrong :-) One other thought is that, I suppose triggering could be handled with an ISR in Lua I suppose? I guess I might worry about how deterministic something like this might be, as well as how many extra clock cycles might go by with such a trigger made in Lua vs some sort of direct hardware configuration or C ISR. I guess one way to know would be to give it a go and see how many samples one might drop between trigger and sampling onset, with different configurations. On Jan 9, 2009, at 2:16 PM, James Snyder wrote: > Overall, those make a good core for the ADC functions. I think a > few additions might be nice as well. > > On Jan 8, 2009, at 3:07 PM, Bogdan Marinescu wrote: > >> Hi, >> >> Following is my proposal for a platform interface for the ADC >> peripheral. I have only very limited experience with ADCs/DACs, in >> fact the only two "serious" applications that I wrote and used ADCs >> were based on external components and were quite basic on the data >> acquisition part, so you might find this specification incomplete >> or just plain strange. If so, please let me know so we can refine >> it to a better form. >> I tried to extract a common set of features of ADCs from all the >> CPUs that eLua currently supports, and this is what I came up with: >> >> - most (or maybe all) of them support both "single shot" and >> "continous" modes >> - some of them let the user select ADC timings (like startup time >> and sample&hold time). This seems to be quite rare though, so I >> won't include it in the platform interface. >> - some of them also support a special mode in which they are >> "paired" with a hardware timer and use that timer as a conversion >> clock. This is useful, and it can be emulated even on platforms >> that don't support this feature. > > I agree with the use of the timer as a conversion clock. > > In a related vein, one thing that I've not used on micros that much, > but have on dedicated ADC boards is the use of triggers for > sampling. This would be particularly useful for burst sampling. > Sometimes this is done based on the signal itself, but often with a > digital trigger. The digital trigger should be pretty easy to do by > having the kickoff be interrupt driven. If a board doesn't support > external interrupts, you could always emulate it by polling, > although it's not as good. > > I guess this brings up the question: do we allow arbitrary pin > selection regardless of whether it will generate interrupts? I have > less knowledge of how this is supported on various 32-bit platforms > that eLua is running on. IIRC, the LM3S boards can do interrupts on > any pin. > >> With this in mind, this is what I came up with: >> >> int platform_adc_exists( unsigned id ); // generic, it will be part >> of src/common.c >> u16 platform_adc_sample( unsigned id ); // sample the specified ADC >> channel > > OK. So this will return the latest sample collected? Does it block > waiting for completion if the latest one hasn't finished yet? > > Also, should this behavior be different in continuous vs single > shot? i.e.: > > Single Shot: wait for sample if not ready > Continuous: take whatever the last completed sample was? wait for > next sample? (I think the former would make more sense as a reason > to use continuous sampling). > > >> void platform_adc_start( unsigned id ); // starts a conversion on >> the specified ADC channel and returns immediately >> int platform_adc_is_done( unsigned id ); // returns 1 if the >> conversion on the specified channel ended, 0 otherwise > > I wonder if in the case of using an interpreted language like Lua > that one might be converting values fast enough that having some > sort of loop waiting for the data to be done might not be fruitful, > at least in single shot mode? Certainly, one is more likely to need > this if one wants to know if a burst has completed. > >> void platform_adc_set_mode( unsigned id, int mode ); // sets the >> mode on the specified ADC channel to either "single shot" or >> "continuous" > > Hmm.. what about adding a filtered/smoothed mode? By this I don't > mean anything particularly intense, perhaps just a ring buffer of a > set length that gets averaged whenever platform_adc_sample is > called. I find myself frequently doing things like this when > sampling things that are noisier than the best resolution the ADC > can deliver. My only thought here would be that the C code might do > this faster than doing the averaging in Lua. > > One way to handle this somewhat elegantly would be to not even add > anything to the mode function, just have the default buffer be of > length 1, and under this condition, no smoothing is done. If you > want it, use the following function to enable the rolling average: > > void platform_adc_set_smoothing( unsigned id, int length ); // sets > window length/buffer size for moving average filter > > Does this seem too much to have in the library? > >> >> void platform_adc_burst( unsigned id, u16* buf, unsigned count, u32 >> frequency ); // burst conversion: read "count" samples from the ADC >> channel "id", storing the results in "buf". The samples are read at >> periodic intervals, the period is given by "frequency". > > I like this as well. > > One thing that might be interesting to provide as well, would be > some method to do this type of recording directly to a binary file > in the mini filesystem or onto an SD card or something similar. > This could be useful if one wants to capture more data than can be > held in SRAM at once, but the sampling rate would have to drop down > to much to record and transfer data a machine connected to the micro. > > > I realize some of these things might extend beyond what could be > appropriate for a simple module, but I think they could be useful > just the same. Also, I think the original functions make sense to > get working as an initial implementation before making any of the > extensions I'm proposing. > > Thoughts? > > > -- > James Snyder > Biomedical Engineering > Northwestern University > jbsnyder at fanplastic.org > http://fanplastic.org/key.txt > ph: (847) 644-2322 > > _______________________________________________ > Elua-dev mailing list > Elua-dev at lists.berlios.de > https://lists.berlios.de/mailman/listinfo/elua-dev -- James Snyder Biomedical Engineering Northwestern University jbsnyder at fanplastic.org http://fanplastic.org/key.txt ph: (847) 644-2322 -------------- next part -------------- An HTML attachment was scrubbed... URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090114/e79a816b/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 194 bytes Desc: This is a digitally signed message part Url : https://lists.berlios.de/pipermail/elua-dev/attachments/20090114/e79a816b/attachment-0001.pgp |
In reply to this post by jbsnyder
> In a related vein, one thing that I've not used on micros that much, but
> have on dedicated ADC boards is the use of triggers for sampling. This > would be particularly useful for burst sampling. Sometimes this is done > based on the signal itself, but often with a digital trigger. The digital > trigger should be pretty easy to do by having the kickoff be interrupt > driven. If a board doesn't support external interrupts, you could always > emulate it by polling, although it's not as good. True, but I don't know much about the possible triggering sources on different platforms, so I don't know how to formulate this into a proper API. > I guess this brings up the question: do we allow arbitrary pin selection > regardless of whether it will generate interrupts? I have less knowledge of > how this is supported on various 32-bit platforms that eLua is running on. > IIRC, the LM3S boards can do interrupts on any pin. Yes, but are any of them possible triggers for the ADC? > With this in mind, this is what I came up with: > > int platform_adc_exists( unsigned id ); // generic, it will be part of > src/common.c > u16 platform_adc_sample( unsigned id ); // sample the specified ADC channel > > OK. So this will return the latest sample collected? Does it block waiting > for completion if the latest one hasn't finished yet? Yes on both questions. > Also, should this behavior be different in continuous vs single shot? i.e.: > Single Shot: wait for sample if not ready > Continuous: take whatever the last completed sample was? wait for next > sample? (I think the former would make more sense as a reason to use > continuous sampling). Not sure yet. I think the difference should be in the "platform_adc_sample" function, which should know how to behave in both 'single' and 'continous' modes. > > void platform_adc_start( unsigned id ); // starts a conversion on the > specified ADC channel and returns immediately > int platform_adc_is_done( unsigned id ); // returns 1 if the conversion on > the specified channel ended, 0 otherwise > > I wonder if in the case of using an interpreted language like Lua that one > might be converting values fast enough that having some sort of loop waiting > for the data to be done might not be fruitful, at least in single shot mode? It might be, but as this is highly dependent on the platform we won't make this assumption, going to the more generic route instead. > void platform_adc_set_mode( unsigned id, int mode ); // sets the mode on the > specified ADC channel to either "single shot" or "continuous" > > Hmm.. what about adding a filtered/smoothed mode? By this I don't mean > anything particularly intense, perhaps just a ring buffer of a set length > that gets averaged whenever platform_adc_sample is called. I find myself > frequently doing things like this when sampling things that are noisier than > the best resolution the ADC can deliver. My only thought here would be that > the C code might do this faster than doing the averaging in Lua. > One way to handle this somewhat elegantly would be to not even add anything > to the mode function, just have the default buffer be of length 1, and under > this condition, no smoothing is done. If you want it, use the following > function to enable the rolling average: > void platform_adc_set_smoothing( unsigned id, int length ); // sets window > length/buffer size for moving average filter > Does this seem too much to have in the library? No, actually this is a very good idea. In all the apps I used so far I needed to implement a moving average filter in order to actually use the data I read from the ADC. Even more, some platforms (like LM3S) have hardware filters, which is even cooler. So yes, let's add this too. > void platform_adc_burst( unsigned id, u16* buf, unsigned count, u32 > frequency ); // burst conversion: read "count" samples from the ADC channel > "id", storing the results in "buf". The samples are read at periodic > intervals, the period is given by "frequency". > > I like this as well. > One thing that might be interesting to provide as well, would be some method > to do this type of recording directly to a binary file in the mini > filesystem or onto an SD card or something similar. This could be useful if > one wants to capture more data than can be held in SRAM at once, but the > sampling rate would have to drop down to much to record and transfer data a > machine connected to the micro. This is a logging application by itself :), and since it could be implemented directly from Lua, let's not do this in the ADC platform interface, it's beyond its purpose. One thing that we could do for this kind of applications is to make the platform_adc_burst function non-blocking, so one can use double buffering (or even better give it another argument to specifiy if it's blocking or not). Something like this: local buf1, buf2 local active = buf1 adc.start_burst( active, ... , adc.NONBLOCKING ) while true do local newactive = active == buf1 and buf2 or buf1 while adc.burst_in_progress( active, ...) do end adc.start_burst( newactive, ... adc.NONBLOCKING ) io.write( active ) active = newactive end I have other ideas about this. Another mode I'm considering is having the ADC acquisition run continously "in the background" (using interrupt handlers) at a given frequency (with averaging if required) and running over a circular buffering mechanism that would provide functions like "get_num_samples", or (when interrupts handlers in Lua are implemented) interrupt triggering at a specified buffer fill rate (in much the same way most UARTs with FIFOs can trigger an interrupt when the FIFO is filled up to a given ratio). It would be much easier to implement double buffering with something like this. But we're not there just yet :) Best, Bogdan > Biomedical Engineering > Northwestern University > jbsnyder at fanplastic.org > http://fanplastic.org/key.txt > ph: (847) 644-2322 > > _______________________________________________ > Elua-dev mailing list > Elua-dev at lists.berlios.de > https://lists.berlios.de/mailman/listinfo/elua-dev > > |
Free forum by Nabble | Edit this page |