2009-06-01 00:22:42 PWM out on gptimer from userspace
Vivek Vaid (UNITED STATES)
Message: 74882
Hello
I am trying to set PWM output on one of the timer pins, from userspace.
I am not able to figure out how to use the functions in: uclinux-dist/linux-2.6.x/arch/blackfin/include/asm/gptimers.h from userspace.
(Upon reading on usage of i2cdriver from userspace (i2c-tools), i guessed that there should be userspace version of gptimers.h. (like there are <linux/i2c-dev.h> for user and kernelspace). ? )
The gptimers wiki page https://docs.blackfin.uclinux.org/doku.php?id=gptimers shows an example of kernelspace. Can it be adapted to userspace?
On my BF537 board, I do get 8 char timer devices in /dev/ after enabling the simple-timer interface, but I am trying to find a reference to how to access them through ioctl or read/write.
Any pointers or help is appreciated.
Thank you,
Vivek
QuoteReplyEditDelete
2009-06-01 00:29:19 Re: PWM out on gptimer from userspace
Mike Frysinger (UNITED STATES)
Message: 74883
the gptimers interface is a kernel API and thus not usable at all from userspace. use the bfin_simple_timer.c char driver.
QuoteReplyEditDelete
2009-06-02 02:44:55 Re: PWM out on gptimer from userspace
Vivek Vaid (UNITED STATES)
Message: 74941
Mike
Thanks.
After Modification of bfin_simple_timer.c, i was able to get pwm-out controlled by ioctl by user-program.
This driver is a great starting point for custom drivers by beginners like me.
I have a minor question. This driver limits the period/duty to 16 bits. Is there any particular reason ? "
case BFIN_SIMPLE_TIMER_SET_PERIOD:
if (arg < 2) return -EFAULT;
n = ((sysclk / 1000) * arg) / 1000;
if (n > 0xFFFF) n = 0xFFFF; /* < ----------period and duty limited to 16bits here */
It would be nice if the limit is removed or moved to 32bits in upcoming version.
Anyway, if I learn how to create/submit patches in time, i will try to update this to a generic one.
Or at-leaset add a simple PWM mode.
Second question -
Currently in my custom driver, i request for a timer pin using constant name (P_TMR5) in function timer_open( ). ie,
...
set_gptimer_config(timer_code[minor].id, PWM_OUT | PERIOD_CNT );
err = peripheral_request(P_TMR5, DRV_NAME); /* <<--how to make it generic like timer_code[minor].id*/
...
Though in my custom hardware these pins can be fixed, but I was wondering how will i make the reference to pin generic.
I am sorry if my post sounds confusing. its quite late.
Thank you,
Best Regards
Vivek
if bored, watch my robot dance: www.youtube.com/watch?v=JqlawTD_9B0
QuoteReplyEditDelete
2009-06-02 02:53:43 Re: PWM out on gptimer from userspace
Mike Frysinger (UNITED STATES)
Message: 74942
the 16bit limit looks like a bug to me. i'll remove it in our svn.
as for the peripheral_request(), i think it makes sense to create a new gptimer_request() function which you pass the timer id and it takes care of calling peripheral_request() on the right pin.
QuoteReplyEditDelete
2009-06-04 00:33:18 Re: PWM out on gptimer from userspace
Vivek Vaid (UNITED STATES)
Message: 75139
Mike,
For my use I created a generic PWM driver derived from the bfin_simple_timer.c driver. I have tested it on my board (custom) , and attached the driver and demo files here.
All this driver does is sets PWM output on the timer pin.
If you find thes files useful, you may include them in SVN for next release. However, i think it can be cleaned up a bit more, but I could not because I am a beginner.
In the process of testing my driver I found some interesting points -
1. Setting pwidth=0, causes 100% Duty output. This is a common bug in most PWM logics in SOCs today which they list as anomaly. However, the BF537 HRM says "0% width is not supported", so it is not an anomaly. (So i added a block for that in my driver. Though an ideal workaround would be to disable the timer when user requests 0% duty. But since its not an official anomaly I didnt implement this workaround.).
Thanks,
Best Regards,
Vivek
pwmtest.c
bfin_pwm_timer.c
bfin_pwm_timer.h
QuoteReplyEditDelete
2009-11-18 21:29:37 Re: PWM out on gptimer from userspace
Craig Jacobson (UNITED STATES)
Message: 82514
Vivek, I've been trying to use this driver.
It's to the point where it seems to be compiled into the kernal. (Couldn't get it to work as a loadable module. Likely due to my ignorance).
However when the pwmtest is run, receive a error: ioctl returned Err =-1.
Have any suggestions? Are there other dependencies? Kernal is based on most recent stable release.
QuoteReplyEditDelete
2010-06-17 12:23:57 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90380
Vivek -
Rather than adding a driver, I made some simple changes to bfin_simple_timer.c for use on BF537 to support separately setting period and width, but I'm not getting any PWM output from the processor. In looking at the gptimers.c code, I don't see where pPORTF_FER is ever set to actually enable the timer outputs. However, your post indicates that you were successful in getting timer output.
Here's my modified code. Can you see any reason why this would not work ? My oscilloscope says that it doesn't...
=============================
static int timer_ioctl(struct inode *inode, struct file *filp, uint cmd, unsigned long arg){
int minor = MINOR(inode->i_rdev);
static unsigned long period, width;
switch (cmd){
case BFIN_SIMPLE_TIMER_SET_PERIOD: // set timer period in microseconds
if (arg < 2) return -EFAULT;
period = ((sysclk / 1000) * arg) / 1000;
set_gptimer_period(timer_code[minor].id, period);
printk("timer_ioctl TIMER_SET_PERIOD: arg=%lu, period=%lu\n", arg, period);
break;
case BFIN_SIMPLE_TIMER_SET_WIDTH: // set timer pulse width in microseconds
if (arg < 2) return -EFAULT;
width = ((sysclk / 1000) * arg) / 1000;
if (width > period) return -EFAULT;
set_gptimer_pwidth(timer_code[minor].id, width);
printk("timer_ioctl TIMER_SET_WIDTH: arg=%lu, width=%lu\n", arg, width);
break;
case BFIN_SIMPLE_TIMER_START:
set_gptimer_config(timer_code[minor].id, PWM_OUT | PERIOD_CNT | PULSE_HI);
enable_gptimers(timer_code[minor].bit);
break;
case BFIN_SIMPLE_TIMER_STOP:
disable_gptimers(timer_code[minor].bit);
break;
case BFIN_SIMPLE_TIMER_READ:
*((unsigned long*)arg) = isr_count[minor];
break;
default:
return -EINVAL;
}
return 0;
}
=============================
Thanks,
Howard
QuoteReplyEditDelete
2010-06-17 12:28:29 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90381
Note that I can successfully access the driver. From my test code, I'm setting timer 2 to 50% duty cycle at 1kHz, and timer 3 to 20% duty cycle at 1kHz
timer_open: device(2) opened
timer_ioctl TIMER_SET_PERIOD: arg=1000, period=121651
timer_ioctl TIMER_SET_WIDTH: arg=500, width=60825
timer_open: device(3) opened
timer_ioctl TIMER_SET_PERIOD: arg=1000, period=121651
timer_ioctl TIMER_SET_WIDTH: arg=200, width=24330
QuoteReplyEditDelete
2010-06-17 13:13:42 Re: PWM out on gptimer from userspace
Mike Frysinger (UNITED STATES)
Message: 90383
no one writes to any PORT registers directly anymore. that is a bug in the driver code if you do. use the portmux framework instead:
https://docs.blackfin.uclinux.org/doku.php?id=portmux
QuoteReplyEditDelete
2010-06-17 14:31:52 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90384
Thanks - that fixed it. This is a bit ugly, but the code works -
static int timer_ioctl(struct inode *inode, struct file *filp, uint cmd, unsigned long arg){
int minor = MINOR(inode->i_rdev);
static unsigned long period, width;
switch (cmd){
case BFIN_SIMPLE_TIMER_SET_PERIOD: // set timer period in microseconds
if (arg < 2) return -EFAULT;
period = ((sysclk / 1000) * arg) / 1000;
set_gptimer_period(timer_code[minor].id, period);
printk("timer_ioctl TIMER_SET_PERIOD: arg=%lu, period=%lu\n", arg, period);
break;
case BFIN_SIMPLE_TIMER_SET_WIDTH: // set timer pulse width in microseconds
if (arg < 2) return -EFAULT;
width = ((sysclk / 1000) * arg) / 1000;
if (width > period) return -EFAULT;
set_gptimer_pwidth(timer_code[minor].id, width);
printk("timer_ioctl TIMER_SET_WIDTH: arg=%lu, width=%lu\n", arg, width);
break;
case BFIN_SIMPLE_TIMER_START:
set_gptimer_config(timer_code[minor].id, PWM_OUT | PERIOD_CNT | PULSE_HI);
enable_gptimers(timer_code[minor].bit);
switch(minor) {
case 2:
peripheral_request(P_TMR2, "/dev/timer");
break;
case 3:
peripheral_request(P_TMR3, "/dev/timer");
break;
case 6:
peripheral_request(P_TMR6, "/dev/timer");
break;
case 7:
peripheral_request(P_TMR7, "/dev/timer");
break;
}
break;
case BFIN_SIMPLE_TIMER_STOP:
disable_gptimers(timer_code[minor].bit);
switch(minor) {
case 2:
peripheral_free(P_TMR2);
break;
case 3:
peripheral_free(P_TMR3);
break;
case 6:
peripheral_free(P_TMR6);
break;
case 7:
peripheral_free(P_TMR7);
break;
}
break;
case BFIN_SIMPLE_TIMER_READ:
*((unsigned long*)arg) = isr_count[minor];
break;
default:
return -EINVAL;
}
return 0;
}
QuoteReplyEditDelete
2010-06-17 14:40:48 Re: PWM out on gptimer from userspace
Robin Getz (UNITED STATES)
Message: 90385
Howard:
Did you miss arch/blackfin/kernel/gptimers.c
It appears what you are looking for is a gptimers-dev or something...
-Robin
QuoteReplyEditDelete
2010-06-17 14:56:14 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90386
Robin -
Right - I'm using bfin_simple_timer.c as the device driver to create /dev/timerx, and that driver is calling functions from gptimers.c. Longer term, we may choose to create a new device driver for the various SRV1 interfaces under the 2009 framework, but for now, I'm trying to get all of the interfaces working. The one that continues to give me trouble is simple-gpio, but I'll post about that in a different thread.
Howard
QuoteReplyEditDelete
2010-07-04 10:45:37 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90878
I thought this was solved with modifications shown above, but I only seem to be able to enable TIMER3 and only rarely have been able to enable TIMER2. Is TIMER2 used elsewhere in the system such that there might be a conflict ? I'm now working from the 2009 uClinux release, though I saw the same problem with 2008.
Here's a snippet of my application code:
tmr2 = open("/dev/timer2", O_RDWR);
if (!tmr2)
puts("unable to open timer2!!");
ioctl(tmr2, BFIN_SIMPLE_TIMER_SET_PERIOD, 1000); // set period to 1000usec = 1kHz
ioctl(tmr2, BFIN_SIMPLE_TIMER_SET_WIDTH, 500); // set width to 500usec = 50% duty cycle
ioctl(tmr2, BFIN_SIMPLE_TIMER_START, 0);
tmr3 = open("/dev/timer3", O_RDWR);
if (!tmr3)
puts("unable to open timer3!!");
ioctl(tmr3, BFIN_SIMPLE_TIMER_SET_PERIOD, 1000); // set period to 1000usec = 1kHz
ioctl(tmr3, BFIN_SIMPLE_TIMER_SET_WIDTH, 500); // set width to 500usec = 50% duty cycle
ioctl(tmr3, BFIN_SIMPLE_TIMER_START, 0);
I added some kprintf's to the driver to trace this and everything looks normal -
timer_ioctl TIMER_SET_PERIOD: arg=1000, period=121651
timer_ioctl TIMER_SET_WIDTH: arg=500, width=60825
timer_ioctl TIMER_START: /dev/timer2
timer_ioctl TIMER_SET_PERIOD: arg=1000, period=121651
timer_ioctl TIMER_SET_WIDTH: arg=500, width=60825
timer_ioctl TIMER_START: /dev/timer3
Any suggestions ?
bfin_simple_timer.h
bfin_simple_timer.c
QuoteReplyEditDelete
2010-07-04 13:24:51 Re: PWM out on gptimer from userspace
Mike Frysinger (UNITED STATES)
Message: 90880
read the /proc/gpio and /proc/interrupt files to figure out what is being used in your configuration
QuoteReplyEditDelete
2010-07-04 14:09:27 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 90881
# cat /proc/interrupts
6: 130165 CORE Blackfin Timer Tick
16: 189 INTN i2c-bfin-twi
18: 0 INTN BFIN_UART_RX
19: 33 INTN BFIN_UART_TX
82: 8 GPIO BFIN_UART_CTS
NMI: 0 CORE Non Maskable Interrupt
Err: 0
# cat /proc/timer_list
Timer List Version: v0.4
HRTIMER_MAX_CLOCK_BASES: 2
now at 124383735000 nsecs
cpu: 0
clock 0:
.base: 005a170c
.index: 0
.resolution: 4000000 nsecs
.get_time: _ktime_get_real
active timers:
clock 1:
.base: 005a1730
.index: 1
.resolution: 4000000 nsecs
.get_time: _ktime_get
active timers:
# cat /proc/gpio
GPIO_0: bfin-uart Peripheral
GPIO_1: bfin-uart Peripheral
GPIO_2: bfin-uart Peripheral
GPIO_3: bfin-uart Peripheral
GPIO_8: blackfin-cam Peripheral
GPIO_9: blackfin-cam Peripheral
Timer2 is GPIO_7, but it's also PPI Frame Sync 3. blackfin_cam.c doesn't seem to be doing anything to FS3 with BF537.
QuoteReplyEditDelete
2010-07-11 20:31:40 Re: PWM out on gptimer from userspace
Howard Gordon (UNITED STATES)
Message: 91151
The code start working when I switched to a different processor card, so the problem is solved. I have tested on various BF537 version 1.0.2 and 1.0.3 boards without seeing a recurrence, so there was just something specific to the board I was using.