I think PWM is an array of integers. If I give pwm+offset, then it will be equivalent to pwm + 4 * offset. Thats why I gave pwm+offset/4 for the correct index of array. Isn't that correct.
On Sun, Apr 6, 2014 at 12:01 PM, Przemek Klosowski < [email protected]> wrote: > Is it possible that your pwm is an array of ints, and you're indexing > it by byte offsets? > I think pwm[OFFSET] is referring to pwm+4*OFFSET, whereas you need > pwm+OFFSET > > On Sun, Apr 6, 2014 at 1:50 AM, milkyway <[email protected]> > wrote: > > I am using GPTIMER_PWM_9 to generate a square wave. Following is my code > > > > #include <stdio.h> > > #include <stdlib.h> > > #include <sys/types.h> > > #include <sys/stat.h> > > #include <unistd.h> > > #include <fcntl.h> > > #include <sys/mman.h> > > > > #define MEMORY_BASE_ADDRESS 0x48000000 > > #define GPTIMER9_BASE_ADDRESS 0x49040000 > > #define GPTIMER9_PADCONF_REGISTER 0x2174/4 > > #define GPTIMER9_RELOAD_REGISTER 0x002c/4 > > #define GPTIMER9_COMAPARATOR_REGISTER 0x0038/4 > > #define GPTIMER9_CONTROL_REGISTER 0x0024/4 > > #define GPTIMER9_COUNTER_REGISTER 0x0028/4 > > > > > > int main(void) > > { > > > > int config_fd, j, pwm_fd; > > volatile unsigned int *config, *pwm;; > > config_fd = open("/dev/mem", O_RDWR | O_SYNC); > > printf ("Open file descriptor for PADCONFIG\n"); > > if (config_fd < 0) > > { > > printf("Could not open PADCONFIG memory fd\n"); > > return 0; > > } > > > > // Pad configuration > > printf ("Setting PAD configuration register\n"); > > config = (unsigned int*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, > > MAP_SHARED, config_fd, MEMORY_BASE_ADDRESS); > > if (config == MAP_FAILED) > > { > > printf("Pinconfig Mapping failed\n"); > > close(config_fd); > > return 1; > > } > > > > printf ("Setting padconf register for PWM\n"); > > config[GPTIMER9_PADCONF_REGISTER] = > config[GPTIMER9_PADCONF_REGISTER] & > > 0xffff0000 | 0x00000002; // setting 0x48002714 as gpt9_pwm_evt > > printf("The pin has been succesfully selected as > gpt9_pwm_evt\n"); > > close(config_fd); > > printf ("Opening file descriptor for PWM\n"); > > pwm_fd = open("/dev/mem", O_RDWR | O_SYNC); > > if (pwm_fd < 0) > > { > > printf("Could not open GPIO memory fd\n"); > > return 2; > > } > > printf ("Memory opened for pwm settings\n"); > > pwm = (unsigned int*) mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, > > MAP_SHARED, pwm_fd, GPTIMER9_BASE_ADDRESS); > > if (pwm == MAP_FAILED) > > { > > printf ("PWM Mapping failed\n"); > > close(pwm_fd); > > return 3; > > } > > printf ("Setting up PWM\n"); > > pwm[GPTIMER9_CONTROL_REGISTER] = 0; > > pwm[GPTIMER9_RELOAD_REGISTER] = 0x0000ff; // initial value of pwm > > during overflow > > pwm[GPTIMER9_COUNTER_REGISTER] = 0x0000ff; // initial value of > pwm > > during overflow > > pwm[GPTIMER9_COMAPARATOR_REGISTER] = 0x0fffff; // overflow value > > pwm[GPTIMER9_CONTROL_REGISTER] = 0x18c3; //timer control > register > > printf ("PWM Started\n"); > > close(pwm_fd); > > return 0; > > } > > > > > > But I am getting an error as follows > > > > root@localhost:/home/dell/sample_programs# ./a.out > > open file descriptor for PADCONFIG > > map PINCONFIG > > Setting padconf register for PWM > > The pin has been succesfully selected as gpt9_pwm_evt > > opening file descriptor for PWM > > Memory opened for pwm settings > > setting up pwm > > Bus error > > > > Can anybody help me to fix this issue? > > > > On Sunday, 13 February 2011 22:11:36 UTC+5:30, mohit hada wrote: > >> > >> 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 : > >> > >> > >> > >> > >> > >> > >> > >> > >> > >> On Sun, Feb 13, 2011 at 6:46 PM, Ben Gamari <[email protected]> > wrote: > >>> > >>> On Sun, 13 Feb 2011 14:14:02 +0530, mohit hada <[email protected]> > wrote: > >>> > 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. > >>> > > >>> 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 > >> > >> > >> > >> > >> -- > >> Mohit Hada (owner) > >> Technid Solutions(An Embedded and FPGA based Design and Development > >> Company) > >> > >> Registered Office : > >> > >> Flat No- 7, > >> 73, Ashutosh Mukherjee Road, > >> Kolkata - 700025 > >> > >> ph : 08820074382 (preferred) / 09322156564 > >> > >> > >> Ass No : 110720200429 > >> > >> Vat No. - 19415754062 > >> > >> > >> > > -- > > For more options, visit http://beagleboard.org/discuss > > --- > > You received this message because you are subscribed to the Google Groups > > "BeagleBoard" group. > > To unsubscribe from this group and stop receiving emails from it, send an > > email to [email protected]. > > For more options, visit https://groups.google.com/d/optout. > > -- > For more options, visit http://beagleboard.org/discuss > --- > You received this message because you are subscribed to a topic in the > Google Groups "BeagleBoard" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/beagleboard/7kLlxZ7fg80/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- For more options, visit http://beagleboard.org/discuss --- You received this message because you are subscribed to the Google Groups "BeagleBoard" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
