HiPi-BCM2835
view release on metacpan or search on metacpan
BCM2835/src/src/bcm2835.c view on Meta::CPAN
if( on )
bcm2835_gpio_set_pud( pin, pud_compat_setting);
}
else
{
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32;
uint8_t shift = pin % 32;
bcm2835_peri_write(paddr, (on ? 1 : 0) << shift);
}
}
/* Read GPIO pad behaviour for groups of GPIOs */
uint32_t bcm2835_gpio_pad(uint8_t group)
{
if (bcm2835_pads == MAP_FAILED)
return 0;
volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group;
return bcm2835_peri_read(paddr);
}
/* Set GPIO pad behaviour for groups of GPIOs
// powerup value for all pads is
// BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA
*/
void bcm2835_gpio_set_pad(uint8_t group, uint32_t control)
{
if (bcm2835_pads == MAP_FAILED)
return;
volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group;
bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD);
}
/* Some convenient arduino-like functions
// milliseconds
*/
void bcm2835_delay(unsigned int millis)
{
struct timespec sleeper;
sleeper.tv_sec = (time_t)(millis / 1000);
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
nanosleep(&sleeper, NULL);
}
/* microseconds */
void bcm2835_delayMicroseconds(uint64_t micros)
{
struct timespec t1;
uint64_t start;
if (debug)
{
/* Cant access sytem timers in debug mode */
printf("bcm2835_delayMicroseconds %lld\n", (long long int) micros);
return;
}
/* Calling nanosleep() takes at least 100-200 us, so use it for
// long waits and use a busy wait on the System Timer for the rest.
*/
start = bcm2835_st_read();
/* Not allowed to access timer registers (result is not as precise)*/
if (start==0)
{
t1.tv_sec = 0;
t1.tv_nsec = 1000 * (long)(micros);
nanosleep(&t1, NULL);
return;
}
if (micros > 450)
{
t1.tv_sec = 0;
t1.tv_nsec = 1000 * (long)(micros - 200);
nanosleep(&t1, NULL);
}
bcm2835_st_delay(start, micros);
}
/*
// Higher level convenience functions
*/
/* Set the state of an output */
void bcm2835_gpio_write(uint8_t pin, uint8_t on)
{
if (on)
bcm2835_gpio_set(pin);
else
bcm2835_gpio_clr(pin);
}
/* Set the state of a all 32 outputs in the mask to on or off */
void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on)
{
if (on)
bcm2835_gpio_set_multi(mask);
else
bcm2835_gpio_clr_multi(mask);
}
/* Set the state of a all 32 outputs in the mask to the values in value */
void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask)
{
bcm2835_gpio_set_multi(value & mask);
bcm2835_gpio_clr_multi((~value) & mask);
}
/* Set the pullup/down resistor for a pin
//
// The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on
// the respective GPIO pins. These registers must be used in conjunction with the GPPUD
// register to effect GPIO Pull-up/down changes. The following sequence of events is
// required:
// 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither
// to remove the current Pull-up/down)
// 2. Wait 150 cycles ? this provides the required set-up time for the control signal
BCM2835/src/src/bcm2835.c view on Meta::CPAN
return data;
} /* bcm2835_smi_read */
/* --------------------------------------------------- */
/* Read the System Timer Counter (64-bits) */
uint64_t bcm2835_st_read(void)
{
volatile uint32_t* paddr;
uint32_t hi, lo;
uint64_t st;
if (bcm2835_st==MAP_FAILED)
return 0;
paddr = bcm2835_st + BCM2835_ST_CHI/4;
hi = bcm2835_peri_read(paddr);
paddr = bcm2835_st + BCM2835_ST_CLO/4;
lo = bcm2835_peri_read(paddr);
paddr = bcm2835_st + BCM2835_ST_CHI/4;
st = bcm2835_peri_read(paddr);
/* Test for overflow */
if (st == hi)
{
st <<= 32;
st += lo;
}
else
{
st <<= 32;
paddr = bcm2835_st + BCM2835_ST_CLO/4;
st += bcm2835_peri_read(paddr);
}
return st;
}
/* Delays for the specified number of microseconds with offset */
void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros)
{
uint64_t compare = offset_micros + micros;
while(bcm2835_st_read() < compare)
;
}
/* PWM */
void bcm2835_pwm_set_clock(uint32_t divisor)
{
if ( bcm2835_clk == MAP_FAILED
|| bcm2835_pwm == MAP_FAILED)
return; /* bcm2835_init() failed or not root */
/* From Gerts code */
divisor &= 0xfff;
/* Stop PWM clock */
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01);
bcm2835_delay(110); /* Prevents clock going slow */
/* Wait for the clock to be not busy */
while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0)
bcm2835_delay(1);
/* set the clock divider and enable PWM clock */
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12));
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */
}
void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled)
{
if ( bcm2835_clk == MAP_FAILED
|| bcm2835_pwm == MAP_FAILED)
return; /* bcm2835_init() failed or not root */
uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL);
if (channel == 0)
{
if (markspace)
control |= BCM2835_PWM0_MS_MODE;
else
control &= ~BCM2835_PWM0_MS_MODE;
if (enabled)
control |= BCM2835_PWM0_ENABLE;
else
control &= ~BCM2835_PWM0_ENABLE;
}
else if (channel == 1)
{
if (markspace)
control |= BCM2835_PWM1_MS_MODE;
else
control &= ~BCM2835_PWM1_MS_MODE;
if (enabled)
control |= BCM2835_PWM1_ENABLE;
else
control &= ~BCM2835_PWM1_ENABLE;
}
/* If you use the barrier here, wierd things happen, and the commands dont work */
bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control);
/* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */
}
void bcm2835_pwm_set_range(uint8_t channel, uint32_t range)
{
if ( bcm2835_clk == MAP_FAILED
|| bcm2835_pwm == MAP_FAILED)
return; /* bcm2835_init() failed or not root */
if (channel == 0)
bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range);
else if (channel == 1)
bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range);
}
void bcm2835_pwm_set_data(uint8_t channel, uint32_t data)
{
if ( bcm2835_clk == MAP_FAILED
|| bcm2835_pwm == MAP_FAILED)
( run in 2.664 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )