generation of square wave form beagle board

Dear Jon,

Where can we get the GPIO update information from the datasheet of DM3730 or OMAP 3530.

I could not find it.

Regards

Mohit

Dear andrey, vladmir,

when I try to run the pwm demo program on the beagle board with angstrom image taken from :

http://processors.wiki.ti.com/index.php/Getting_Started_With_C6Run_On_Beagleboard

I get the following error :

root@beagleboard:~# ./pwm-demo
[ 174.893035] Unhandled fault: external abort on non-linefetch (0x1818) at 0x4001e024
Bus error

Please tell me some remedy of this… running a simple gpio program did run on the BB-xM fine.

regards

A little bit of Googling goes a long ways:

  http://e2e.ti.com/support/embedded/f/354/p/49197/196854.aspx
  http://markmail.org/message/dzcyrbqkeeivesyq
  http://linux.omap.com/pipermail/linux-omap-open-source/2007-November/012094.html

The problem is apparently that your pwm demo doesn't enable the PWM
unit's clocks before accessing the PWM. You should take a look at
section 16.2 to determine which clocks are needed.

- Ben

Hi,

as far as I remember, this error happens if you have
CONFIG_OMAP_RESET_CLOCKS enabled in the kernel. You can check
following kernel module, but it does exactly the same as library you
are using.

https://github.com/scottellis/omap3-pwm

At the bottom of the page, there is a notice with the setting which
should be disabled. So, you need to rebuild the kernel with this
option.

Regards,
Maksym.

Hi to all

Thanks a lot Ben for your help in your last mail…

Now I have been able to generate PWM but on beagle board xM, I have been able to generate maximum 4.34 MHz… The code modified is given
below, my added parts are indicated separately. But Now My doubt is why I get so low value of 4.34 MHz with 26MHz system clock. Is it that I am not able to use 26 MHz or ??? Please help. Thanks…

omap3530-pwm-demo.c :

#include <glib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include “omap3530-pwm.h”

int
main(int argc, char **argv)
{
int mem_fd;
int i;

/* New addition written by mohit */
volatile ulong *pinconf, *clk_selec;

mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
pinconf = (ulong*)mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0x48000000);
if (pinconf == MAP_FAILED) {
printf(“Pinconf Mapping failed\n”);
close(mem_fd);
return 0;
}

pinconf[0x2174/4] = 0x011A011A; //PIN CONFIGURED AS BIDIRECTIONAL
pinconf[0x2178/4] = 0x011A011A; //PIN CONFIGURED AS BIDIRECTIONAL
close(mem_fd);

mem_fd = pwm_open_devmem();

if (mem_fd == -1) {
// g_error(“Unable to open /dev/mem, are you root?: %s”, g_strerror(errno));
}

pwm_clkfreq_sel(mem_fd, TRUE, TRUE);
pwm_close_devmem(mem_fd);

/program end by mohit/

mem_fd = pwm_open_devmem();

if (mem_fd == -1) {
// g_error(“Unable to open /dev/mem, are you root?: %s”, g_strerror(errno));
}

////////////////////////////////INCLUSION OF ADDITIONAL FUNCTION CALLS FOR FCLK AND ICLK ENABLE///////////////////////////////////////////////////////

// ENABLE ICLK CLOCK
pwm_iclken_clock(mem_fd, TRUE, TRUE);
pwm_close_devmem(mem_fd);

mem_fd = pwm_open_devmem();

if (mem_fd == -1) {
// g_error(“Unable to open /dev/mem, are you root?: %s”, g_strerror(errno));
}

// ENABLE FCLK CLOCK
pwm_fclken_clock(mem_fd, TRUE, TRUE);
pwm_close_devmem(mem_fd);

mem_fd = pwm_open_devmem();

if (mem_fd == -1) {
// g_error(“Unable to open /dev/mem, are you root?: %s”, g_strerror(errno));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Set instances 10 and 11 to use the 13 Mhz clock
pwm_config_clock(mem_fd, TRUE, TRUE);
guint8 *gpt10 = pwm_mmap_instance(mem_fd, 10);
guint8 *gpt11 = pwm_mmap_instance(mem_fd, 11);

// Get the resolution for 20 kHz PWM
guint32 resolution = pwm_calc_resolution(20000000, PWM_FREQUENCY_13MHZ);

// Ramp up and down a bit
for(i = 0; i <= 100; i++) {
// g_print("%3d\n", i);
pwm_config_timer(gpt10, resolution, i / 100.0);
pwm_config_timer(gpt11, resolution, i / 100.0);
usleep(100000);
}
sleep(500);
for (i = 100; i >= 0; i–) {
// g_print("%3d\n", i);
pwm_config_timer(gpt10, resolution, i / 100.0);
pwm_config_timer(gpt11, resolution, i / 100.0);
usleep(100000);
}

pwm_munmap_instance(gpt10);
pwm_munmap_instance(gpt11);
pwm_close_devmem(mem_fd);
}

// vim: set ts=4 et :

omap3530-pwm.c :

#include <glib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>

#include “omap3530-pwm.h”

// Clock configuration registers (TRM p. 470)
#define CM_CLKSEL_CORE 0x48004A40
#define CLKSEL_GPT10_MASK (1 << 6)
#define CLKSEL_GPT11_MASK (1 << 7)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define CM_CLKSEL_FCLK 0x48004A00
#define FCLKSEL_GPT10_MASK (1 << 11)
#define FCLKSEL_GPT11_MASK (1 << 12)

#define CM_CLKSEL_ICLK 0x48004A10
#define ICLKSEL_GPT10_MASK (1 << 11)
#define ICLKSEL_GPT11_MASK (1 << 12)

#define CLKFREQ_SEL 0x48306D40
#define BIT1 (1 << 1)
#define BIT0 (1 << 0)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// GPTIMER register offsets
#define GPT_REG_TCLR 0x024
#define GPT_REG_TCRR 0x028
#define GPT_REG_TLDR 0x02c
#define GPT_REG_TMAR 0x038

// Get a guint32 pointer to the register in block instance at byte
// offset offset.
#define REG32_PTR(instance, offset) ((volatile guint32*) (instance + offset))

// General purpose timer instances. Not all of these can actually be
// used for PWM — see the TRM for more information.
static guint32 gpt_instance_addrs[] = {
0x4903e000, // GPTIMER8
0x49040000, // GPTIMER9
0x48086000, // GPTIMER10
0x48088000, // GPTIMER11
};

// The default Linux page size is 4k and the GP timer register
// blocks are aligned to 4k. Therefore it is convenient to just
// assume that pages are aligned there for the purposes of mmap()
// (since mmap only maps aligned pages). This function checks
// that assumption and aborts if it is untrue.
static void
check_pagesize(void)
{
if (getpagesize() != 4096) {
// g_error(“The page size is %d. Must be 4096.”, getpagesize());
}
}

// Simply a wrapper around mmap that passes the correct arguments
// for mapping a register block. instance_number must be between
// 1 and 12, or errno will be set to EDOM and MAP_FAILED returned.
// Otherwise the return value is that of mmap().
guint8*
pwm_mmap_instance(int mem_fd, int instance_number)
{
if (instance_number < 8 || instance_number > 11) {
errno = EDOM;
return MAP_FAILED;
}
int instance_addr = gpt_instance_addrs[instance_number - 8];
return mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, instance_addr);
}

// The inverse of pwm_mmap_instance(), this is simply a wrapper
// arount munmap(). It returns the underlying munmap() call’s
// return value.
int
pwm_munmap_instance(guint8 *instance)
{
return munmap(instance, 4096);
}

// Configure the clocks for GPTIMER10 and GPTIMER11, which can be set to
// use the 13 MHz system clock (otherwise they use the 32 kHz clock like
// the rest of the timers). Return -1 on failure, with errno set.
int
pwm_config_clock(int mem_fd, gboolean gptimer10_13mhz, gboolean gptimer11_13mhz)
{
int page_addr = CM_CLKSEL_CORE & 0xfffff000;
int offset = CM_CLKSEL_CORE & 0xfff;

guint8 *registers = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, page_addr);
if (registers == MAP_FAILED) {
return -1;
}

guint32 value = *REG32_PTR(registers, offset);
value &= ~(CLKSEL_GPT10_MASK | CLKSEL_GPT11_MASK);
if (gptimer10_13mhz) value |= CLKSEL_GPT10_MASK;
if (gptimer11_13mhz) value |= CLKSEL_GPT11_MASK;
*REG32_PTR(registers, offset) = value;

return munmap(registers, 4096);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int
pwm_fclken_clock(int mem_fd, gboolean gptimer10_13mhz, gboolean gptimer11_13mhz)
{
int page_addr = CM_CLKSEL_FCLK & 0xfffff000;
int offset = CM_CLKSEL_FCLK & 0xfff;

guint8 *registers = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, page_addr);
if (registers == MAP_FAILED) {
return -1;
}

guint32 value = *REG32_PTR(registers, offset);
value &= ~(FCLKSEL_GPT10_MASK | FCLKSEL_GPT11_MASK);
if (gptimer10_13mhz) value |= FCLKSEL_GPT10_MASK;
if (gptimer11_13mhz) value |= FCLKSEL_GPT11_MASK;
*REG32_PTR(registers, offset) = value;

return munmap(registers, 4096);
}

int
pwm_iclken_clock(int mem_fd, gboolean gptimer10_13mhz, gboolean gptimer11_13mhz)
{
int page_addr = CM_CLKSEL_ICLK & 0xfffff000;
int offset = CM_CLKSEL_ICLK & 0xfff;

guint8 *registers = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, page_addr);
if (registers == MAP_FAILED) {
return -1;
}

guint32 value = *REG32_PTR(registers, offset);
value &= ~(ICLKSEL_GPT10_MASK | ICLKSEL_GPT11_MASK);
if (gptimer10_13mhz) value |= ICLKSEL_GPT10_MASK;
if (gptimer11_13mhz) value |= ICLKSEL_GPT11_MASK;
*REG32_PTR(registers, offset) = value;

return munmap(registers, 4096);
}

int
pwm_clkfreq_sel(int mem_fd, gboolean gptimer10_13mhz, gboolean gptimer11_13mhz)
{
int page_addr = CLKFREQ_SEL & 0xfffff000;
int offset = CLKFREQ_SEL & 0xfff;

guint8 *registers = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, page_addr);
if (registers == MAP_FAILED) {
return -1;
}

guint32 value = *REG32_PTR(registers, offset);
value &= ~(BIT1 | BIT0);
if (gptimer10_13mhz) value |= BIT1;
if (gptimer11_13mhz) value |= BIT0;
*REG32_PTR(registers, offset) = value;

return munmap(registers, 4096);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Calculate the resolution of the PWM (the number of clock ticks
// in the period), which is passed to pwm_config_timer().
guint32
pwm_calc_resolution(int pwm_frequency, int clock_frequency)
{
float pwm_period = 1.0 / pwm_frequency;
float clock_period = 1.0 / clock_frequency;
return (guint32) (pwm_period / clock_period);
}

// Initialize the control registers of the specified timer
// instance for PWM at the specified resolution.
void
pwm_config_timer(guint8 *instance, guint32 resolution, float duty_cycle)
{
guint32 counter_start = 0xffffffff - resolution;
guint32 dc = 0xffffffff - ((guint32) (resolution * duty_cycle));

// Edge condition: the duty cycle is set within two units of the overflow
// value. Loading the register with this value shouldn’t be done (TRM 16.2.4.6).
if (0xffffffff - dc <= 2) {
dc = 0xffffffff - 2;
}

// Edge condition: TMAR will be set to within two units of the overflow
// value. This means that the resolution is extremely low, which doesn’t
// really make sense, but whatever.
if (0xffffffff - counter_start <= 2) {
counter_start = 0xffffffff - 2;
}

*REG32_PTR(instance, GPT_REG_TCLR) = 0; // Turn off
*REG32_PTR(instance, GPT_REG_TCRR) = counter_start;
*REG32_PTR(instance, GPT_REG_TLDR) = counter_start;
*REG32_PTR(instance, GPT_REG_TMAR) = dc;
*REG32_PTR(instance, GPT_REG_TCLR) = (
(1 << 0) | // ST – enable counter
(1 << 1) | // AR – autoreload on overflow
(1 << 6) | // CE – compare enabled
(1 << 7) | // SCPWM – invert pulse
(2 << 10) | // TRG – overflow and match trigger
(1 << 12) // PT – toggle PWM mode
);
}

int
pwm_open_devmem(void)
{
check_pagesize();

return open("/dev/mem", O_RDWR | O_SYNC);
}

void
pwm_close_devmem(int dev_fd)
{
/* This function is useful! */
close(dev_fd);
}

// vim: set ts=4 expandtab :

mohit hada wrote:

Hi jon,

i think you are right since when i do not give any delay between toggling the GPIO pins from
user space, I got just 2 MHz....

Now I have a doubt will i get this as maximum speed while reading data form GPIO as well, for e.g.
If using an external interrupt signal, if I want to read 12 bit data on GPIO pins coming from Analog to
Digital Converter, will the maximum speed limit to 2 MHz. Please tell me.

see: http://groups.google.com/group/beagleboard/msg/c6d8cbd23fc46873

and the whole discussion thread:

http://groups.google.com/group/beagleboard/browse_thread/thread/de6f0d17b8d0c418?tvc=2

Dear Vladmir,

The reply of soren tells that 4Mbps is the last on the GPIO which I can get… so i have to drop the idea of using GPIO…
in fact i have to leave BB- xM for this project…

But one doubt I still have if you can resolve… why this link then tells that faster GPIO access can be done using DMA…??

https://e2e.ti.com/support/dsp/omap_applications_processors/f/447/p/49018/183185.aspx

As I was trying to explore that option.

Regards

Mohit

Hi vladmir,

Again I dont know why i could not get higher than around 4.34MHz through PWM.

regards

mohit

[snip]

  A brief scan of S16 of the TRM would have told you that if you:

  - Set timer clock to some suitable frequency, up to 38.4MHz
  - Set the timer count to something suitable and timer to
     auto-reload
  - Program GPTi.TCLR to generate a pulse, or set 'toggle on overflow'

  You can get a square wave of more or less any frequency you like.
I haven't checked the pads, but I'd be surprised if there wasn't
some PWM GPIO which wouldn't cope with 20MHz.

  Odd duty cycles are less straightforward ..

  If you want higher frequencies, you can get 216MHz / (0..31) from
the ISP CLKA or CLKB pins.

Richard.

mohit hada wrote:

Dear Vladmir,

The reply of soren tells that 4Mbps is the last on the GPIO which I can get..... so i have to drop the idea of using
GPIO....
in fact i have to leave BB- xM for this project.....

well, you have to drop the idea of connecting your ADC over GPIO, why not use one that works over SPI? Or McBSP?

But one doubt I still have if you can resolve.... why this link then tells that faster GPIO access can be done using DMA..??

Why is the LM2904 behaving this way? - Amplifiers forum - Amplifiers - TI E2E support forums

I have no idea.

mohit hada wrote:

Hi vladmir,

Again I dont know why i could not get higher than around 4.34MHz through PWM.

I don't know.

but maybe you can tell us what you need that 20MHz output clock for?

Dear Vladmir,

The reply of soren tells that 4Mbps is the last on the GPIO which I can
get..... so i have to drop the idea of using GPIO....
in fact i have to leave BB- xM for this project.....

That is for GPIO usage. The PWM should do what you want. Blindly
Googling for things like this will only further cloud the issue. You
really just need to sit down and read the relevant section of the TRM
(chapter 16).

But one doubt I still have if you can resolve.... why this link then tells
that faster GPIO access can be done using DMA..??

You'll need to look through chapter 9 of the TRM and see what the
capabilities of the DMA unit are. I wasn't aware that the DMA controller
could drive the GPIOs.

Really though, you should either use the PWM or dedicated
hardware. Using GPIO to produce a simple waveform like this is just
insane.

- Ben

Hi Ben and Vladmir,

I want to sample an analog input using a 12 bit ADC at around 20 Msps so I want 240Mbps of data input rate. So the start of conversion signal for the ADC, ADS 2807 has to be the square wave.

The reason I am not using McBSP or not choosing an SPI based ADC is that, Beagle Board can give only 48Mbps serially at the max which is much lower to my requirement.

So I am stuck…

regards

the ADC is parallal ADC and the square wave is 20MHz i.e. start of conversion signal of ADC.

And the port that I have to use to connect parallal ADC is external peripheral header …

mohit hada wrote:

Hi Ben and Vladmir,

I want to sample an analog input using a 12 bit ADC at around 20 Msps so I want 240Mbps of data input rate. So the start
of conversion signal for the ADC, ADS 2807 has to be the square wave.

besides capturing, what do you want to do with that 240Mbps of data?

The reason I am not using McBSP or not choosing an SPI based ADC is that, Beagle Board can give only 48Mbps serially
at the max which is much lower to my requirement.

then maybe indeed the BB is not the right hardware for you...

In that case, here is an exercise for you: read the TRM and spot a
parallel interface that will accept 20 Msps of 12-bit data. It has
a whole chapter to itself and everything ..

Richard.

Hi Ben and Vladmir,

I want to sample an analog input using a 12 bit ADC at around 20 Msps so I
want 240Mbps of data input rate. So the start of conversion signal for the
ADC, ADS 2807 has to be the square wave.

Ouch. That is a very high number. In fact, I believe it's a pretty large
fraction of the memory bandwidth of the OMAP. What do you intend on
doing with this data once you get it onto the device? I don't think
you'll have a lot of headroom computationally.

The reason I am not using McBSP or not choosing an SPI based ADC is that,
Beagle Board can give only 48Mbps serially at the max which is much lower
to my requirement.

So I am stuck...

Pretty much. I don't believe there's any way the BeagleBoard could
satisfy those requirements. As far as I know there simply isn't an
interface that could support that data rate (although I could be wrong).

That being said, you should look at the PandaBoard. It's an OMAP4-based
board which exposes the General-Purpose Memory Controller (at least
16-bits of it). I believe you'd need some dedicated logic to look after
the ADC (which shouldn't be a surprise given the data rate you are
looking for). Perhaps you could use an FPGA to push samples into a RAM
as well as multiplex reads from the GPMC. You could then perhaps use the
sDMA controller to pull memory over the GPMC into local memory. Just a
(perhaps fatally flawed) thought.

Cheers,

- Ben

I, for one, am stumped. Which interface would this be? Looking through
the ToC of the TRM, the only thing I can see is the GPMC. Perhaps
another hint is in order?

- Ben

To be fair, it does depend on your timing requirements, but the
ISP is quite capable of sampling at 20 MHz (VGA dot clock is
25, SD TV clocks 27). You just frame your problem as a video sampling one,
arrange for your syncs to be in (more or less) the right places
and away you go.

  240Mbps is only 80 MByte/s - my USB attached hard disc can do 30%
of that (admittedly on a Panda, but still).

  Now, if you want 240MByte/s you might have a problem.. :slight_smile:

Richard.