RetroBSD

2.11BSD operating system for microcontrollers
It is currently Tue Mar 31, 2020 2:37 am

All times are UTC




Post new topic Reply to topic  [ 26 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: usleep() issues in i2c
PostPosted: Sun Sep 27, 2015 7:11 am 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
While I messed with i2c.h, trying to use usleep(usecs) to delay the transitions, I observed weird behaviour - it slowed down significantly, even stopped for a while.
It seems usleep() does not work properly when called too often.
I had to use for_loop as the delay instead.

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Mon Sep 28, 2015 3:03 pm 
Contributor

Joined: Mon Nov 12, 2012 1:34 pm
Posts: 1092
Hi Pito,

The whole small delay stuff is quite a problem.

Like you I often wind up doing the loop solution.

It seems that usleep and friends say the delay will be at least X.

Then the OS turns it into Y seconds plus X which is not what is usually needed.

The other thing often missing is the 'dispatch' command that says I am done for a bit and tells the OS that it can now run for a while. Typically until the next interrupt or timer event.

This is especially problematic for telephony type stuff. You want regular 8khz samples from and to ADC DAC but you need to make the CPU slow enough to really talk to the hardware. Bascially I have RetroBSD running under a sort of real time kernel. So I get real time stuff to work and can use the higher level functions from BSD easily.

I continue to be amazed by the 'real time' stuff provided by some vendors who in my humble opinion don't know about the real problems.

So like you I write my own :).

Then it just works! What a concept!

Lots of fun.

Wiz


Top
 Profile  
 
PostPosted: Mon Sep 28, 2015 7:04 pm 
Committer
User avatar

Joined: Wed Oct 10, 2012 11:01 pm
Posts: 1081
Location: Sunnyvale, CA
Pito wrote:
While I messed with i2c.h, trying to use usleep(usecs) to delay the transitions, I observed weird behaviour - it slowed down significantly, even stopped for a while.
It seems usleep() does not work properly when called too often.

It's not an issue of usleep() by itself. It does what it does: suspends the process fir a minimum of given number of microseconds. Don't forget: there are other activities in the system, not only your application. For example, update and cron daemons also need to be activated from time to time. It causes some amount of swapping, so your application will be delayed for a few hundred of milliseconds.

In case you cannot tolerate the jitter, it's better to consider to put your stuff inside the kernel. Internally, the kernel _is_ real time. All you need is to develop a kernel service or a driver, interacting with the rest of the kernel via the existing API. Any good book on Unix drivers can help.

I would propose "Writing Device Drivers: Tutorial and Reference" by Al Wojtas and others. While based on DEC OSF/1 operating system, it's still applicable to RetroBSD and LiteBSD, and in general it provides an excellent background for the kernel internals.


Top
 Profile  
 
PostPosted: Tue Sep 29, 2015 6:06 pm 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
So we need a driver for hw i2c - to eliminate the need for usleep.

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Wed Oct 07, 2015 10:34 pm 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
Do we have udelay() somewhere (for SmallerC)??

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Thu Oct 08, 2015 6:53 am 
Committer
User avatar

Joined: Wed Oct 10, 2012 11:01 pm
Posts: 1081
Location: Sunnyvale, CA
No, we don't have udelay() implemented in user mode. But technically it's possible: COP0 Count register value can be obtained using RDHWR instruction. I had not yet tested it myself, but it should be something like:
Code:
unsigned c0_count()
{
    asm ("rdhwr $2, $2");
}

void udelay(unsigned usec)
{
    unsigned now = c0_count();
    unsigned final = now + usec * (CPU_KHZ / 1000) / 2;
           
    for (;;) {
        now = c0_count();
        if ((int) (now - final) >= 0)
            break;
    }
}


Top
 Profile  
 
PostPosted: Thu Oct 08, 2015 5:51 pm 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
Thanks, it seems it works inside i2c.h.
The Q is how to get the CPU_KHZ value into the code..

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Thu Oct 08, 2015 6:56 pm 
Committer
User avatar

Joined: Wed Oct 10, 2012 11:01 pm
Posts: 1081
Location: Sunnyvale, CA
The sysctl() system call is supposed to be used for this purpose.
Turned out, these parameters were missing, so I added them: see this change.
So now it's possible to query the cpu and bus frequencies from command line:
Code:
# sysctl machdep.cpu_khz
machdep.cpu_khz = 80000
# sysctl machdep.bus_khz
machdep.bus_khz = 80000

From C program, use the following code:
Code:
#include <stdio.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>

int cpu_khz()
{
    int mib[2], khz;
    size_t size;

    mib[0] = CTL_MACHDEP;
    mib[1] = CPU_FREQ_KHZ;
    size = sizeof(khz);
    if (sysctl(mib, 2, &khz, &size, NULL, 0) < 0) {
        perror("sysctl");
        return -1;
    }
    return khz;
}

int main()
{
    printf("cpu_khz = %d\n", cpu_khz());
    return 0;
}


Top
 Profile  
 
PostPosted: Thu Oct 08, 2015 7:32 pm 
Committer
User avatar

Joined: Wed Oct 10, 2012 11:01 pm
Posts: 1081
Location: Sunnyvale, CA
BTW, I just found a bug in the kernel's udelay() routine.
It used CPU_KHZ/1000 as a multiply factor, which is twice more than required.
The point is, the Count register is increased at half clock speed.
So I had fixed it in the kernel, and modified the above example.
Please, update your sources as well.


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 2:04 am 
Contributor

Joined: Mon Nov 12, 2012 1:34 pm
Posts: 1092
Hi Serge and all,

I suppose another useful feature from user space especially in test drivers would be:

Disable interrupts [and OS]
Do whatever VIA direct low level I/O
Loop type delays
Get driver low level results
Enable interrupts
Report results up the chain to the OS.
Tell the OS, it's your turn -- Dispatch or whatever

I am not sure whether Retro/Lite has these commands available from user space, but IMHO is should :).

I think the more or less conventional idea that all hardware can only be talked to from kernel space is not a very good idea and certainly makes device driver development MUCH more difficult.

Wiz


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 6:18 am 
Committer
User avatar

Joined: Wed Oct 10, 2012 11:01 pm
Posts: 1081
Location: Sunnyvale, CA
Hi Wiz,

In brief: no.
The whole idea of building reliable systems is based on a concept of protecting a hardware and low level activities from users.

Imagine you take a plane and find out that during the flight any passenger is free to enter a pilot's cabin, and turn any wheels and press any buttons he wants, and then tell the pilot: OK, I'm done, you can continue to drive the jalopy. Surely you would have a lot of fun during such flight. :)

Best wishes,
--Serge


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 8:21 am 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
delay.h
Code:
// delay.h
// udelay() msdelay() msecs() usecs() cpus()
// for SmallerC

#include <stdio.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>

int cpu_khz()
{
    int mib[2], khz;
    size_t size;

    mib[0] = CTL_MACHDEP;
    mib[1] = CPU_FREQ_KHZ;
    size = sizeof(khz);
    if (sysctl(mib, 2, &khz, &size, NULL, 0) < 0) {
        perror("sysctl");
        return -1;
    }
    return khz;
}

int bus_khz()
{
    int mib[2], khz;
    size_t size;

    mib[0] = CTL_MACHDEP;
    mib[1] = CPU_BUS_KHZ;
    size = sizeof(khz);
    if (sysctl(mib, 2, &khz, &size, NULL, 0) < 0) {
        perror("sysctl");
        return -1;
    }
    return khz;
}

unsigned c0_count()
{
    asm ("rdhwr $2, $2");
}

void udelay(unsigned usec)
{
    unsigned now = c0_count();
    unsigned final = now + (usec * cpu_khz() / 2000);
           
    for (;;) {
        now = c0_count();
        if ((int) (now - final) >= 0)
            break;
    }
}

void msdelay(unsigned mssec)
{
    unsigned now = c0_count();
    unsigned final = now + (mssec * cpu_khz() / 2);
           
    for (;;) {
        now = c0_count();
        if ((int) (now - final) >= 0)
            break;
    }
}

unsigned cpus()
{
    unsigned now = c0_count();
    return (now * 2);
}

unsigned usecs()
{
    unsigned now = c0_count();
    return (now * 2000 / cpu_khz());
}

unsigned msecs()
{
    unsigned now = c0_count();
    return (now * 2 / cpu_khz());
}

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 9:19 am 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
Trying to compile with i2c.h with delay.h under SmallerC (latest unix.hex and filesystem).
Code:
# cat i2c.h
// I2C() - a simple bitbanging
// Pito 10/2015
// based on http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
#include "pins.h"
#include "delay.h"
// Fubarino SD - SDA pin D10, SCL pin D11
..

#define DL 3

void I2CInit(){
        sda_od;
        scl_od;
        udelay(DL);
        sdacl_out_0;
        udelay(DL);
..

Code:
# make
cc  -o rtc8563rd  rtc8563rd.c
/include/sys/proc.h:82: error: out of macro space!
*** Exit 1

Stop.
#

Code:
# cc -o bmp BMP085rd.c -lm
/include/sys/proc.h:82: error: out of macro space!
#

Code:
# cc -o i2cscan i2cscan.c
/include/sys/proc.h:82: error: out of macro space!
#

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 9:57 am 
Committer
User avatar

Joined: Thu Oct 11, 2012 8:45 am
Posts: 1801
Location: Room 217, Floor 8, Arm 8, Wheel S7, Mars Base Alpha 3
vak wrote:
Hi Wiz,

In brief: no.
The whole idea of building reliable systems is based on a concept of protecting a hardware and low level activities from users.

Imagine you take a plane and find out that during the flight any passenger is free to enter a pilot's cabin, and turn any wheels and press any buttons he wants, and then tell the pilot: OK, I'm done, you can continue to drive the jalopy. Surely you would have a lot of fun during such flight. :)

Best wishes,
--Serge

These kids these days just don't get the basic theory of OS programming, do they?

In simple terms, Wiz, what you are proposing is reprogramming a Google self-drive car so you can mow down children in a parking lot (give me full control of all aspects of the car and I'll hand it back to you when I have killed enough children and smashed you into a brick wall - and then expect you to drive off like nothing happened).

It is neither a good idea or something that would leave your Google self-drive car in a working state afterwards.

_________________
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 9:59 am 
Committer
User avatar

Joined: Thu Oct 11, 2012 8:45 am
Posts: 1801
Location: Room 217, Floor 8, Arm 8, Wheel S7, Mars Base Alpha 3
Pito wrote:
delay.h
Code:
// delay.h
// udelay() msdelay() msecs() usecs() cpus()
// for SmallerC

#include <stdio.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>

int cpu_khz()
{
  ... random code sliced mercilessly out of the quote ...
}

Non-static non-inline functions in a header file?! Are you insane?!

_________________
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 10:40 am 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
What is wrong with the header file? It is included in the *.c as is..

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 11:12 am 
Committer
User avatar

Joined: Thu Oct 11, 2012 8:45 am
Posts: 1801
Location: Room 217, Floor 8, Arm 8, Wheel S7, Mars Base Alpha 3
Imagine what would happen if your program consisted of two C files and they both wanted to use your header.

_________________
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 11:42 am 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
You may try:
Code:
# cat testdel.c
#include "delay.h"
int main() {
   unsigned dl, ms, us;
   dl = 1000000;

    ms = msecs();
    us = usecs();

    udelay(dl);

    us = usecs() - us;
    ms = msecs() - ms;

    printf("us= %d ms= %d\r\n", us, ms);

return 0;
}

Code:
# cc -o tst testdel.c
# ./tst
us= -73570 ms= 463
#

So it compiles, but still is something going wrong.
The above error while compiling comes from SmallerC, I assume..

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 12:12 pm 
Committer
User avatar

Joined: Thu Oct 11, 2012 8:45 am
Posts: 1801
Location: Room 217, Floor 8, Arm 8, Wheel S7, Mars Base Alpha 3
Try this:

Code:
// testdel1.c
#include "delay.h"
extern void dodelay();

int main() {
    udelay(1000);
    dodelay();
    return 0;
}


Code:
// testdel2.c
#include "delay.h"

void dodelay() {
    udelay(1000);
}


Code:
$ cc -o tst testdel1.c testdel2.c

_________________
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".


Top
 Profile  
 
PostPosted: Fri Oct 09, 2015 3:45 pm 
Contributor
User avatar

Joined: Thu Nov 08, 2012 7:04 am
Posts: 2401
Location: Rapa Nui
This works:
Code:
#include "delay.h"

int main() {

unsigned dl, ms1, us1, ms, us;

dl = 100000;

ms1 = msecs();
us1 = usecs();

udelay(dl);

us = usecs();
ms = msecs();

printf("us1= %d ms1= %d\r\n", us1, ms1);
printf("us= %d ms= %d\r\n", us, ms);

us = us - us1;
ms = ms - ms1;

printf("use= %d mse= %d\r\n", us, ms);

return 0;
}

Code:
# # cc -o tst testdel.c
# ./tst
us1= 23194 ms1= 413413
us= 123367 ms= 413514
use= 100173 mse= 101
#


With del=1000000
Code:
# ./tst
us1= 318078 ms1= 179632
us= 244539 ms= 180096
use= -73539 mse= 464
#

I can hardly imagine the c0 counter can ovverrun in 1sec with 4MHz increment.

_________________
Pukao Hats Cleaning Services Ltd.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 26 posts ]  Go to page 1, 2  Next

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
cron




Powered by phpBB® Forum Software © phpBB Group

BSD Daemon used with permission