ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am writing some programs that interface with hardware in assembly.I really need a timer that goes to at least 1ms .Even lower would be better. The only thing I can come up with is assembly language programming of the 8253 timer,but I can't seem to figure it out.Here is a simple program I'm trying to write to test the timer.
You are correct about the unwieldy syntax for the inline assembler. Since you are intent on playing with hardware at this low level, I'll assume you are not planning to run this under Linux, or other protected mode OS (if you are, then your problems are just beginning...). So, since you are programming right to the metal, why not use a cross assembler, such as NASM and generate DOS executables, or executables that run standalone? Is this intended to even run on a PC architecture at all, or on some other x86 pltform?
More specific to your problem, a question? Are you planning to generate interrupts, or just tickle some hardware? On a PC, the Channel 1 that your code is accessing will play havoc with RAM refresh, and may well crash any modern PC. Some oldies, like '286 & '386 architectures tended to be tolerant of this kind of pokery, but I wouldn't count on that with today's designs. If you want to generate interrupts at 1KHz, you will need to use channel 0, and write 04h to the MSB, and A9h to the LSB. This will result in a 1.5% error, due to the clock frequency not being an exact integer multiple of 1000. Handling the interrupts may require managing the 8259 Interrupt Controller, along with of course, invoking whatever it is you want to do 1000 times per scond.
I used to do this kind of stuff with my eyes closed, but its been so many years, I don't remember all the details. Tell me a little more about the architecture and purpose of your adventure, and I'm sure I can help. I will scan some old disks and what-have-you tonight, and see if I can't come up with some old working code.
Not homework, just a hobby. I need this to time data coming from the parallel port right now, but later I think it will come in handy elsewhere.I really wanted a DOS(Freedos) executable but I wrote the rest of the program already.I was looking for a DOS cross compiler but that's another story.Until I get a C cross compiler to make a DOS executable I'm going to use linux.I just need the timing portion.I really don't want to rewrite everything. I was planning to use it in linux anyway.Are you saying it won't work?I have had this problem on a lot of programs.I need to time the signals but I can't. If I could it would improve a lot of my work, not just this project. Hard to believe with all the megahertz signals inside a pc I can't access one of them for timing.
Could you give me some advice to solve the problem?
The more convenient the better.
Maybe a game library would have these timers for C?
In Linux, you don't have the liberty of accessing hardware freely like you do in a real-mode OS like DOS. In order to protect itself and other processes, the kernel uses facilties built into the the CPU to prohibit access to hardware and absolute memory addresses. In particular, I think the OS uses the timer interrupt in a PC architecture to invoke the kernel's task switching mechanism on an interrupt driven basis (as distinct from an OS like Windows, which is primarily a cooperative multitasking OS, AFAIK). Linux does provide it's own source of high resolution timers available through system calls. Do man gettimeofday for details on one of them.
I did manage to dig out a DOS MASM compatible source file that seems to do what you want. It assembles to a MS C-callable object module that allows you to speed up the 8253 timer interrupt by an arbitrary power of 2, and provides hooks to allow it to update a counter variable at the accelerated rate. It's a bit long, so I'm loath to post it here, but if you think it would be helpful, I could get it to you another way. If any moderators are listening, maybe they could comment on guidleines for this sort of thing.
It would be a great match to have Linux as a development environment for freedos.
I've been busy doing other stuff though.
I think I have a way to read the signal ,but I still need that timer.
Here is what I'm trying now.
Code:
here is what the sgnals look like.
_ ____
| | | =0
|_| |
S S
_ _
| | | =1
|____| |
S S
So a one is at least ten times longer low from start to stop.
for(int i=0;i<9;i++)
{
while(port is high)high++;
while(port is low)low++;
if (high >10*low)byte|(1<<i);
}
What do you think?
I'm still working on the timing.
I have other applications for the timer even if I don't need it here.
I don't think I will go with that assembly code.
Thanks for explaining it to me anyway.
If there was a way to time a loop maybe?
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
cyb0rg,
This is never gonna work in plain Linux. First you cannot talk to the hardware directly, secondly the kernel might dedicate its time to another task instead of yours and you might never know it.
You either have to switch to RT Linux or to writing a device driver. RT Linux is nice, but you'll have to dedicate your entire machine to the task. A device driver can communicate with the hardware in real-time and that might be what you need. But I think writing a device driver is difficult if you don't have a starting point in the form of an existing driver.
You might want to look into the Comedi libraries. Small timing delays are implemented with usleep() which are perfect for the timing intervals you are looking for. I am not sure whether there is a Comedi driver for the parallel port. If not it might give you a starting point though.
What you say about you preference of having a DOS app is true. I wrote many control programs in DOS. However I came to prefer writing them in Linux using Comedi, even using the same hardware.
Thanks for the reply ,
The comedi drivers look like they might work. I'll look into them a bit.
I'm using some really old computers (166mhz) to do my tests.
I have slackware installed on one and vector linux on another.
I don't think there is a distribution of RT linux that would replace those?
What about the code example I posted ,it should work ,right?
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
Quote:
Originally Posted by cyb0rg777
Thanks for the reply ,
The comedi drivers look like they might work. I'll look into them a bit.
I'm using some really old computers (166mhz) to do my tests.
Are you kidding? I developed my first Comedi application om a P166. 2x8 bit digital I/O and 2 channels analog, sampled and processed that with a 5 ms clock and never even noticed processor load.
Quote:
Originally Posted by cyb0rg777
I have slackware installed on one and vector linux on another.
I don't think there is a distribution of RT linux that would replace those?
Yes, it replaces your distro That is, you put RT linux on it and you don't have another distro installed anymore and you can't do real work on the either.
The decision whether you use RTLinux or Comedi device drivers is whether you need guaranteed response time. And I don't mean on the driver level. You do have guaranteed times to measure useconds etc. Guaranteed response is after your application reads the bytes from the driver, your need a minimum response time. For example if you detect overcurrent, and you'd have to decide to open a switch. You need RTL for that. If you can wait 100-200 ms worst case (like switching on an indicator in a user panel) Comedi is fine. I never saw response times over 50 ms on a P700 running Debian (w/o GUI that is)
Quote:
Originally Posted by cyb0rg777
What about the code example I posted ,it should work ,right?
Not in Linux, but perhaps in DOS. I am not good in code tracing, I use gdb an see what happens
Timing loops are a poor way to do measurements, even under a quasi-OS like DOS, which does have all sorts of things going on that consume arbitrary amounts of CPU as interrupt handlers.
A better algorithm would seem to be, something like:
Code:
foreach bit{
loop( while no start edge )
grab time[start]
loop( while no data edge )
grab time[data]
loop( while no stop edge )
grab time[stop]
if( ( time[stop] - time[data] ) < 10 * ( time[data] - time[start] ) ) then
bit = 1
else
bit = 0
endif
}
The 'grab time' statement would be the part where you either read a hardware timer, or get some measure of time from the OS, like gettimeofday() as I suggested earlier. This will probably be quite reliable on signals where a bit time is in the order of 100s of microseconds or longer, even on a non-realtime OS. If you have a realtime OS, you might simply spawn a periodic task to read the data line level (perhaps doing multiple reads per interval, for noise immunity), and use the periodicity of the task timing to measure time.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.