I want to control LED diod with PWM using bcm2835.h and pure C langueage. My code does not work. What am I missing?
I have tried "gpio" console command and it works fine, so I know that led is connected to the right ports. I can turn it on using console command:
gpio pwm 1 1024
My code:
#include <bcm2835.h>
#include <stdio.h>
// PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18) in alt fun 5.
// Note that this is the _only_ PWM pin available on the RPi IO headers
#define PIN RPI_GPIO_P1_12
// and it is controlled by PWM channel 0
#define PWM_CHANNEL 0
// This controls the max range of the PWM signal
#define RANGE 1024
int main(int argc, char **argv)
{
if (!bcm2835_init())
{
return 1;
}
// Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);
// Clock divider is set to 16.
// With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
// the pulse repetition frequency will be
// 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1);
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE);
while(1)
{
bcm2835_pwm_set_data(PWM_CHANNEL, 1024);
bcm2835_delay(10);
}
bcm2835_close();
return 0;
}
I expect that my LED will turn on.
This is stupid, but after checking the math, code, wiring I discovered that app needs to be run with root privileges to have on-board access to the pins. It works fine. Topic can be closed.
Related
I am doing a major embedded project of making a GM counter. As a main microcontroller I am using a PIC32MK1024MCM064. I wont bore you with details, but I need to implement following algorithm:
When MCU turns on, 13 seconds delay has to pass
MCU waits for a button press, which triggers an interrupt
Button interrupt starts 60 seconds timer
During that 60 seconds, MCU input pin counts the impulses (Idle voltage state is high (3.3V) and low voltage state counts as an impulse (50-130 us duration))
After the timer has expired, MCU outputs the impulse number via 16x2 LCD screen
Project has many files included in it, but I have already verified all the peripheral code is written right:
I have already made sure, that my button interrupt and the timer interrupt work absolutely fine (used the oscilloscope, real timer and all the other stuff.)
I also verified that my I2C driver for the LCD screen works great as well.
I made sure I am indeed getting the low state impulses as defined (50-130 us duration.)
#include <xc.h>
#include "configurations_bits.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "stdio.h"
#include <sys/attribs.h>
#include "delay.h"
#include "inter_integrated_circuit_protocol.h"
#include "liquid_crystal_display.h"
#include "pulse_width_modulation.h"
#include "timer.h"
#include "state_change_interrupts.h"
static int Particle_count = 0; //Variable for counting events
char Value[10]={0}; //Particle value string
int main(void) {
__builtin_disable_interrupts(); //Global interrupt disable
ANSELA = 0x00000000; //Enable PORT A digital inputs
ANSELG = 0x00000000; //Enable PORT G digital inputs
TRISEbits.TRISE12 = 0; //Output gpio of a led
TRISDbits.TRISD8 = 0; //Output gpio of a led
TRISGbits.TRISG9 = 0; //Output GPIO of GM ENABLE
LATGbits.LATG9 = 1; //Enable GM right away
TRISAbits.TRISA1 = 1; //Input for counting particles
TRISCbits.TRISC7 = 1; //Input for control button
Inter_Integrated_Circuit_Setup (); //I2C configuration
Inter_Integrated_Circuit_Enable (); //I2C enable
Liquid_Crystal_Display_initialization(); //LCD configuration
Liquid_Crystal_Display_Set_Cursor(1, 1);
Liquid_Crystal_Display_Write_String("Preparing for");
Liquid_Crystal_Display_Set_Cursor(2, 1);
Liquid_Crystal_Display_Write_String("Measurement");
Pulse_Width_Modulation_Setup(); //PWM setup
Pulse_Width_Modulation_Enable(); //Turn on high voltage generation
for(int i=0; i<13; i++){
delay_ms(1000);} //Waiting until the high voltage rail rises up to 400V (starting GM tube voltage)
Liquid_Crystal_Display_Clear(); //Clearing LCD
Liquid_Crystal_Display_Set_Cursor(1, 1);
Liquid_Crystal_Display_Write_String("Ready for");
Liquid_Crystal_Display_Set_Cursor(2, 1);
Liquid_Crystal_Display_Write_String("Measurement");
State_Change_Interrupts_Setup (); //Button interrupt setup
Timer2_Setup (); //Timer interrupt setup
__builtin_enable_interrupts(); //Global interrupt enable
while (1){
if(T2CONbits.ON){ //Condition, that the timer is on
Liquid_Crystal_Display_Clear(); //Clearing LCD
Liquid_Crystal_Display_Set_Cursor(1, 1);
Liquid_Crystal_Display_Write_String(" Measurement Is ");
Liquid_Crystal_Display_Set_Cursor(2, 1);
Liquid_Crystal_Display_Write_String(" In Progress ");
while(T2CONbits.ON){ //Execute this while cycle until the timer shuts off
if(PORTAbits.RA1==0){
Particle_count = Particle_count+1;
delay_us(100);} //GM tube dead time compensation
}
Liquid_Crystal_Display_Clear(); //Clearing LCD
sprintf(Value,"%05d CPM",Particle_count);
Particle_count=0; //Resetting the CPM value
Liquid_Crystal_Display_Set_Cursor(1, 1);
Liquid_Crystal_Display_Write_String(Value);//Printing radiation level in CPM notation
delay_ms(5000);
Liquid_Crystal_Display_Clear(); //Clearing LCD
}
}
return (EXIT_FAILURE);
}
When I press the button, my LCD outputs "Measurement Is In Progress" for a fraction of a second, then it immediately outputs "00000 CPM" which means it had counted zero impulses (In my application, I know for sure that I must capture at least 5 impulses per minute.) Looks like the while cycle has only one or few iterations (it should last for a minute). So my code problem is not a missing semicolon somewhere, but I feel like the whole architecture is not right. Have you got any observations or suggestions, how could I implement the mentioned algorithm? Want to thank you in advance.
(P.S I am running a 8 MHz internal FRC as the main clock)
I am developing a simple program to run a buzzer in AVR on a Teensy 2.0 (ATMEGA32u4) and I am having great difficulty getting the PWM output to work. The PWM output is on PB6 and I can test it digitally so I am not worried about the hardware setup of the buzzer.
Eventually, the PWM will have a 50% duty cycle and the frequency will modulate, however, I am more concerned I am not getting any output at this point.
I have tried several different PWM setups and even have a second timer running to complete other tasks.
Here is my setup and program skeleton:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void button_handler(void);
void setup(void)
{
cli(); // Disable interrupts
// Set sysclk to 16 MHz
CLKPR = (1<<CLKPCE); // Prescaler change enable
CLKPR = 0x00; // Set prescaler to zero
DDRB = (1<<DDB6); // configure PORT B6 (buzzer) as output
// initliase timer1
// Fast PWM, TOP = OCR1A, Update OCR1B at TOP, TOV1 flag set on TOP
// Clear OC1B on compare match, set OC1B at TOP
// clkI/O/1 (No prescaling)
TCCR1A = (1<<COM1B1)|(1<<WGM11)|(1<<WGM10);
TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS10);
OCR1A = 1023; // Setup PWM Registers
OCR1B = 511; // 50% duty cycle
sei(); // Enable interrupts
}
int main(void)
{
setup(); // initialise device
for (;;)
{
// runs led blinking on PORTD, removed for simplicity
}
}
Really struggling to see where I am going wrong so any help would be much appreciated!
Finally managed a fix coming back after a few months, a simple clean fixed the issue.
I am working on using Raspberry Pi to generate hardware PWM to control my stepper motors. When I tried hardware pwm, I found that I can not control the pulse in numbers such as I just wanted motor to move 8000 steps and then stop.
I don't want use time to turn off the PWM, I want specific steps.
#include <bcm2835.h>
#include <stdio.h>
// PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18)
// in alt fun 5.
// Note that this is the _only_ PWM pin available on the RPi IO headers
#define PIN RPI_GPIO_P1_12
// and it is controlled by PWM channel 0
#define PWM_CHANNEL 0
// This controls the max range of the PWM signal
#define RANGE 1024
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
// Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);
// Clock divider is set to 16.
// With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
// the pulse repetition frequency will be
// 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); //CTL reg
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); //RNG1/2 reg
// Vary the PWM m/s ratio between 1/RANGE and (RANGE-1)/RANGE
int direction = 1;
int data = 1;
while (1)
{
if (data == 1)
direction = 1;
else if (data == RANGE-1)
direction = -1;
data += direction;
bcm2835_pwm_set_data(PWM_CHANNEL, data);
bcm2835_delay(1);
}
bcm2835_close();
return 0;
}
Can this code achieve my thought (modifying some registers of pwm)? Which reg of PWM control the autofill(autopadding), I just want to know how to stop sending pulses after stopping the motor.
I am working with the Microsemi Smartfusion2 development kit from Arrow. It uses the Smartfusion2 M2S010-FG484 FPGA. (https://www.arrow.com/en/products/sf2plus-dev-kit/arrow-development-tools)
I am new to the Smartfusion2, I am trying to establish a connection between the Smartfusion2 FPGA and Arduino using the microcontroller subsystem (MSS) and programing ti in Softconsole. The problem is that I can't seem to get it to work. While trying to debug, I attached an LED (i had to improvise since I don't have an oscilloscope) to pin 3 of the arduino connector (J2) on the development board. This pin should contain the slave select 3 (pin J18 on the FPGA) as indicated in the datasheet on page 16 (https://static4.arrow.com/-/media/images/part-detail-pages/sf2-plus/new-sf2-files/sf2plus_user_guide_v1p1.pdf?la=zh-cn) and in the I/O editor of Libero SoC.
With the following code I am trying to toggle the LED/Select and deselect the specified slave (Slave 3). But nothing happens. The Slave select is active low but the LED is always on and never turns off.
/*
* main.c
*
* Created on: Aug 16, 2017
*/
#include "drivers/mss_gpio/mss_gpio.h"
#include "drivers/mss_spi/mss_spi.h"
#include <stdio.h>
/*Delay function in milliseconds, for 100MHz clock*/
void Delay(uint32_t Delayms){
uint32_t i = 0;
uint32_t DelayValue = Delayms*2000; //1000ms*100000 = 100000000 (100MHz)
for(i = 0; i <= DelayValue; i++){
}
}
/*Configuration for SPI0*/
void ConfigSPI1(void){
/*Initialize and Configure SPI1*/
MSS_SPI_init(&g_mss_spi1);
MSS_SPI_disable(&g_mss_spi1); //Disable SPI1
/*Configure SPI1 as master, protocol mode, clk speed, frame size*/
MSS_SPI_configure_master_mode(
&g_mss_spi1, //Selects SPI1 for configuration
MSS_SPI_SLAVE_3, //Set the target device as slave 3
MSS_SPI_MODE2, //Serial peripheral interface operating mode
64u, //Divider used on APB bus (PCLK) clock in order to generate the SPI clock
12); //Number of bits making up the frame, max = 32
MSS_SPI_enable(&g_mss_spi1); //Enable SPI1
}
/*SPI0 test function*/
void SPI1Test(void){
MSS_SPI_set_slave_select(&g_mss_spi1, MSS_SPI_SLAVE_3); //Used by a MSS SPI master to select a specific slave
MSS_SPI_transfer_frame(&g_mss_spi1, 0xaaa); //Transfers "0xaaa" to the selected slave (slave 3)
Delay(1000); // I used this delay for testing, to keep the SS low for a longer time to be able to see the LED turn off
MSS_SPI_clear_slave_select(&g_mss_spi1, MSS_SPI_SLAVE_3); //Used by a MSS SPI master to deselect a specific slave
}
int main(){
/*Configure modules*/
ConfigSPI1();
/*Infinite loop*/
for(;;){
SPI1Test();
Delay(3000);
}
return 0;
}
Does anyone see a mistake in my code that might be causing the problem? or maybe have an working example code for me?
I wrote another program to toggle pin J18/the slave select 3 pin with the gpio driver, and that worked, it toggled the LED. I am also pretty certain that the design in Libero SoC is correct and imported correctly.
Thank you for your time!
I tried controlling the servo with softPwm using the wiringPi Library but this made the servo stutter.
Therefore I want to use the hardware PWM pin on the Raspberry Pi (GPIO18) with the wiringPi library.
But I don't understand how to set the frequency to 50 Hz and change the duty cycle to have a pulse width ranging from 0.8 ms to 2.5 ms.
I found the following relationship on the internet (i dont know if it is correct):
pwmFrequency in Hz = 19.2e6 Hz / pwmClock / pwmRange.
i know the clock divisor max value is something around 4000 and the Raspberry Pi PWM clock has a base frequency of 19.2 MHz. so this gives me ~4,8KHz.
i already got these settings which should give me ~50Hz using the following relationship:
//put PWM in mark-space mode, which will give you
//the traditional (and easily predictable) PWM
pwmSetMode(PWM_MODE_MS);
//setting ping GPIO 18 as a pwm output
pinMode(18,PWM_OUTPUT);
//Set clock divisor to 4000
pwmSetClock(4000);
pwmSetRange (10) ;
I dont got a oscilloscope to test the output signal to check what setting changes what. this makes it hard to find it out myself.
Long story short:
Can anyone tell me how I can achieve a duty cycle with a pulse width of 0,8ms to 2,1ms for controlling a servo using the hardware PWM on the Raspberry Pi.
I'm a complete newby to Pi and to Servo's. But I got it to work with wiringPi.
It says here that we're looking to create pulse of 1ms to 2ms in length, every 20ms or so. Assuming this 19.2Mhz base clock is indeed correct, setting pwm clock to 400 and pwm range to 1000, should give a pulse at 48Hz or every 20.8 ms. Then setting pwm value to 48 should give you a 1ms long pulse and a pwm value of 96 should give you a 2ms long pulse.
But you need to set the chip in pwm-ms mode.
(Lots of shoulds here, since I do not have an osciolloscope either)
So to set it up:
gpio mode 1 pwm
gpio pwm-ms
gpio pwmc 400
gpio pwmr 1000
And then you can turn the servo from left to right via
gpio pwm 1 48
gpio pwm 1 96
(Actually, the servo I got worked from 28 up to 118; could be the servo)
(The setup sequence seems important; could be a bug)
if (wiringPiSetup () == -1) //using wPi pin numbering
exit (1) ;
pinMode(1, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);
pwmSetClock(384); //clock at 50kHz (20us tick)
pwmSetRange(1000); //range at 1000 ticks (20ms)
pwmWrite(1, 75); //theretically 50 (1ms) to 100 (2ms) on my servo 30-130 works ok
return 0 ;
Make sure you are using correct gpio pins!
Models A and B have one hardware PWM on pin 18 BCM (1 wPi).
Models A+ and B+ can output second hardware pwm on pins 13 and 19 BCM (23, 24 wPi)
How about using RPIO instead? Here's the link to the library: http://pythonhosted.org/RPIO/index.html
Here's the PWM example: http://pythonhosted.org/RPIO/pwm_py.html
And you may also use the C source directly: https://github.com/metachris/RPIO/tree/master/source/c_pwm
I got wiringPi to do it through software bit-banging. I might have tried RPIO but my particular application requires that the audio output works, and I understand that RPIO's DMA makes audio go away. I might have also tried wiringPi's softPwm or even softServo, but I also require to run a DC motor through PWM, and I don't want to bring the whole system down to 50Hz just for the servo.
This program worked as a demonstration, has no jitter (because it doesn't continuously drive the positioning pulses), and lands on its target each time with a visibly indistinguishable error. Granted the Pi isn't doing much else at the time to interfere with the program's timing (except running an X server through SSH, gedit, terminal session, everything in top, etc.).
// Servo trial 11/15/14 by SLC
#include <wiringPi.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
wiringPiSetup();
pinMode( 6, OUTPUT );
digitalWrite( 6, HIGH );
int idx = 0, tries = 0;
while ( tries++ < 30 )
{
int i;
const int period[] = { 500, 1500, 2500 };
printf( "Setting period to %i ms\n", period[idx] );
for ( i = 0; i < 20; ++i )
{
// Output going through an inverter (to convert 3.3V to 5V)
digitalWrite( 6, LOW );
usleep( period[idx] );
digitalWrite( 6, HIGH );
usleep( 20 * 1000 );
}
++idx;
idx %= 3;
sleep( 2 );
}
}
My servo is a Radio Shack Micro Servo, which appears identical to the other "micro" servos out there. I also found I could ditch the inverter and just drive the signal using the 3.3V GPIO.