void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) { 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 (channel == 0) bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); else if (channel == 1) bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); }
// Read an number of bytes from I2C uint8_t bcm2835_i2c_read(char* buf, uint32_t len) { volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; uint32_t remaining = len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); // Set Data Length bcm2835_peri_write_nb(dlen, len); // Start read bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) { while (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) { // Read from FIFO, no barrier buf[i] = bcm2835_peri_read_nb(fifo); i++; remaining--; } // When remaining data is to be received, then wait for a fully FIFO if (remaining >= BCM2835_BSC_FIFO_SIZE) delayMicroseconds(i2c_byte_wait_us * BCM2835_BSC_FIFO_SIZE); else delayMicroseconds(i2c_byte_wait_us * remaining); } // Received a NACK if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { reason = BCM2835_I2C_REASON_ERROR_CLKT; } // Not all data is received else if (remaining) { reason = BCM2835_I2C_REASON_ERROR_DATA; } bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) { 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_DATA, data); else if (channel == 1) bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); }
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); }
// Writes an number of bytes to SPI void bcm2835_spi_writenb(char* tbuf, uint32_t len) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; // This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); uint32_t i; for (i = 0; i < len; i++) { // Maybe wait for TXD while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO, no barrier bcm2835_peri_write_nb(fifo, tbuf[i]); } // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) { 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); }
/* Writes (and reads) a single byte to SPI */ uint8_t bcm2835_spi_transfer(uint8_t value) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t ret; /* This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); /* Set TA = 1 */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); /* Maybe wait for TXD */ while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) ; /* Write to FIFO, no barrier */ bcm2835_peri_write_nb(fifo, value); /* Wait for DONE to be set */ while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) ; /* Read any byte that was sent back by the slave while we sere sending to it */ ret = bcm2835_peri_read_nb(fifo); /* Set TA = 0, and also set the barrier */ bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); return ret; }
void bcm2835_spi_begin(uint8_t cs) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS / 4; DBG_MSG("IN cs=%d\n", cs); // Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them // except if we need custom Chip Select Pin // printf("bcm2835_spi_begin -> spi_custom_cs = %d \n",cs ); // Do we need custom chip select control or // drive CE1 manually (because CE1 does not work with hardware) if ( cs > BCM2835_SPI_CS_NONE || cs == BCM2835_SPI_CS1 ) { // indicate we will use a custom GPIO port spi_custom_cs = cs ; // ok hard CE1 not working, drive it manually if (cs == BCM2835_SPI_CS1) { // Dirty Hack CE1 in now custom Chip Select GPIO 26 // the real CE1 pin spi_custom_cs = RPI_GPIO_P1_26; bcm2835_gpio_fsel(spi_custom_cs, BCM2835_GPIO_FSEL_OUTP); // BCM2835_GPIO_FSEL_OUTP=0b001 bcm2835_gpio_write(spi_custom_cs, HIGH); } // Mask in we use custom CS (not sure it has a real effect) bcm2835_peri_set_bits(paddr, BCM2835_SPI_CS_NONE, BCM2835_SPI0_CS_CS); } // Ok hardware driving of chip select else { // Just in case spi_custom_cs = 0 ; // Mask in the CS bits of CS bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); } // Now we can drive the I/O as asked if (spi_custom_cs == 0) { // Not custom CS, so hardware driven bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0 bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1 } else { // so set custom CS as output, High level by default bcm2835_gpio_fsel(spi_custom_cs, BCM2835_GPIO_FSEL_OUTP); // Custom GPIO bcm2835_gpio_write(spi_custom_cs, HIGH); } // Classic pin, hardware driven bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); // MISO bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // MOSI bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); // CLK // Set the SPI CS register to the some sensible defaults bcm2835_peri_write(paddr, 0); // All 0s // Clear TX and RX fifos bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); }
//void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value); /// Call bcm2835_peri_write_nb with 2 parameter /// \par Refer /// \par Modify void ope_peri_write_nb(void) { volatile uint32_t* paddr; uint32_t value; get_int_code(); get_int_code(); paddr = *((volatile uint32_t **)(buff+1)); value = *((volatile uint32_t *)(buff+5)); bcm2835_peri_write_nb( paddr, value ); }
// initialization of GPIO and SPI // ---------------------------------------------------------- void TFT_init_board ( void ) { // *************** set the pins to be an output and turn them on bcm2835_gpio_fsel( OE, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( OE, HIGH ); bcm2835_gpio_fsel( RAIO_RST, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( RAIO_RST, HIGH ); bcm2835_gpio_fsel( RAIO_CS, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( RAIO_CS, HIGH ); bcm2835_gpio_fsel( RAIO_RS, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( RAIO_RS, HIGH ); bcm2835_gpio_fsel( RAIO_WR, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( RAIO_WR, HIGH ); bcm2835_gpio_fsel( RAIO_RD, BCM2835_GPIO_FSEL_OUTP ); bcm2835_gpio_write( RAIO_RD, HIGH ); // *************** now the inputs bcm2835_gpio_fsel( RAIO_WAIT, BCM2835_GPIO_FSEL_INPT ); bcm2835_gpio_set_pud( RAIO_WAIT, BCM2835_GPIO_PUD_UP); bcm2835_gpio_fsel( RAIO_INT, BCM2835_GPIO_FSEL_INPT ); bcm2835_gpio_set_pud( RAIO_INT, BCM2835_GPIO_PUD_UP); // *************** set pins for SPI bcm2835_gpio_fsel(MISO, BCM2835_GPIO_FSEL_ALT0); bcm2835_gpio_fsel(MOSI, BCM2835_GPIO_FSEL_ALT0); bcm2835_gpio_fsel(SCLK, BCM2835_GPIO_FSEL_ALT0); bcm2835_gpio_fsel(SPI_CE1, BCM2835_GPIO_FSEL_ALT0); // set the SPI CS register to the some sensible defaults volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/8; bcm2835_peri_write( paddr, 0 ); // All 0s // clear TX and RX fifos bcm2835_peri_write_nb( paddr, BCM2835_SPI0_CS_CLEAR ); bcm2835_spi_setBitOrder( BCM2835_SPI_BIT_ORDER_MSBFIRST ); bcm2835_spi_setDataMode( BCM2835_SPI_MODE0 ); bcm2835_spi_setClockDivider( BCM2835_SPI_CLOCK_DIVIDER_2 ); bcm2835_spi_chipSelect( BCM2835_SPI_CS1 ); bcm2835_spi_setChipSelectPolarity( BCM2835_SPI_CS1, LOW ); }
// Writes an number of bytes to SPI void spi_uart_tx(char c) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); //BUG: The start bit is always 1.5 periods long, probably unfixable // This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); // Maybe wait for TXD while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO, no barrier bcm2835_peri_write_nb(fifo, reverse_bits(c)); // Read from FIFO to prevent stalling while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read_nb(fifo); // bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { // while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) // (void) bcm2835_peri_read_nb(fifo); } // bcm2835_delayMicroseconds(10); // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); //TODO: THe program might be interrupted in here, corrupting the character. bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_OUTP); // MOSI bcm2835_gpio_set(RPI_GPIO_P1_19); //idle high bcm2835_gpio_set_pud(RPI_GPIO_P1_19,BCM2835_GPIO_PUD_UP); bcm2835_delayMicroseconds(40); }
void bcm2835_spi_begin(void) { // Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1 bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0 bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); // MISO bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // MOSI bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); // CLK // Set the SPI CS register to the some sensible defaults volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; bcm2835_peri_write(paddr, 0); // All 0s // Clear TX and RX fifos bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); }
uint8_t bcm2835_spi_send(uint8_t value) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; /* Maybe wait for TXD */ while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)); /* Write to FIFO, no barrier */ bcm2835_peri_write_nb(fifo, value); /* Wait for DONE to be set */ while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)); /* Read any byte that was sent back by the slave while we sere sending to it */ return bcm2835_peri_read_nb(fifo); }
// --------------------------------------------------------------------------- // Enables SPI function on default GPIOs. // --------------------------------------------------------------------------- void bcm2835_spi_open( void ) { // This driver uses the default pins with GPFSEL alternative function ALT0. bcm2835_gpio_fsel( SPI_GPIO_CE0, BCM2835_GPFSEL_ALT0 ); bcm2835_gpio_fsel( SPI_GPIO_CE1, BCM2835_GPFSEL_ALT0 ); bcm2835_gpio_fsel( SPI_GPIO_MISO, BCM2835_GPFSEL_ALT0 ); bcm2835_gpio_fsel( SPI_GPIO_MOSI, BCM2835_GPFSEL_ALT0 ); bcm2835_gpio_fsel( SPI_GPIO_CLK, BCM2835_GPFSEL_ALT0 ); // Set SPI CS register to default values (0). volatile uint32_t *paddr; paddr = bcm2835_spi0 + BCM2835_SPI0_CS / 4; bcm2835_peri_write( paddr, 0 ); // Clear FIFOs. bcm2835_peri_write_nb( paddr, BCM2835_SPIO_CS_CLEAR ); }
void bcm2835_spi_begin(void) { volatile uint32_t* paddr; /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ /* Set the SPI CS register to the some sensible defaults */ paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; bcm2835_peri_write(paddr, 0); /* All 0s */ /* Clear TX and RX fifos */ bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); }
/* Writes an number of bytes to SPI */ void bcm2835_spi_writenb(char* tbuf, uint32_t len) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t i; /* This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Answer: an ISR is required to issue the required memory barriers. */ /* Clear TX and RX fifos */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); /* Set TA = 1 */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); for (i = 0; i < len; i++) { /* Maybe wait for TXD */ while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) ; /* Write to FIFO, no barrier */ bcm2835_peri_write_nb(fifo, tbuf[i]); /* Read from FIFO to prevent stalling */ while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read_nb(fifo); } /* Wait for DONE to be set */ while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read_nb(fifo); }; /* Set TA = 0, and also set the barrier */ bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
/* Writes (and reads) an number of bytes to SPI */ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t TXCnt=0; uint32_t RXCnt=0; /* This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? */ /* Clear TX and RX fifos */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); /* Set TA = 1 */ bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); /* Use the FIFO's to reduce the interbyte times */ while((TXCnt < len)||(RXCnt < len)) { /* TX fifo not full, so add some more bytes */ while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) { bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); TXCnt++; } /* Rx fifo not empty, so get the next received bytes */ while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) { rbuf[RXCnt] = bcm2835_peri_read_nb(fifo); RXCnt++; } } /* Wait for DONE to be set */ while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) ; /* Set TA = 0, and also set the barrier */ bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
// Writes (and reads) a single byte to SPI uint8_t bcm2835_spi_transfer(uint8_t value) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; // Custom chip select LOW bcm2835_spi_setChipSelect(LOW); // This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); // Maybe wait for TXD while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) delayMicroseconds(10); // Write to FIFO, no barrier bcm2835_peri_write_nb(fifo, value); // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) delayMicroseconds(10); // Read any byte that was sent back by the slave while we sere sending to it uint32_t ret = bcm2835_peri_read_nb(fifo); // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); // Custom chip select HIGH bcm2835_spi_setChipSelect(HIGH); return ret; }
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); */ }
// Sending an arbitrary number of bytes before issuing a repeated start // (with no prior stop) and reading a response. Some devices require this behavior. uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) { #ifdef I2C_V1 volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; #endif uint32_t remaining = cmds_len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); // Set Data Length bcm2835_peri_write_nb(dlen, cmds_len); // pre populate FIFO with max buffer while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) { bcm2835_peri_write_nb(fifo, cmds[i]); i++; remaining--; } // Enable device and start transfer bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); // poll for transfer has started (way to do repeated start, from BCM2835 datasheet) while ( !( bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TA ) ) { // Linux may cause us to miss entire transfer stage if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) break; } remaining = buf_len; i = 0; // Send a repeated start with read bit set in address bcm2835_peri_write_nb(dlen, buf_len); bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); // Wait for write to complete and first byte back. bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); // wait for transfer to complete while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { // we must empty the FIFO as it is populated and not use any delay while (remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) { // Read from FIFO, no barrier buf[i] = bcm2835_peri_read_nb(fifo); i++; remaining--; } } // transfer has finished - grab any remaining stuff in FIFO while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) { // Read from FIFO, no barrier buf[i] = bcm2835_peri_read_nb(fifo); i++; remaining--; } // Received a NACK if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { reason = BCM2835_I2C_REASON_ERROR_CLKT; } // Not all data is sent else if (remaining) { reason = BCM2835_I2C_REASON_ERROR_DATA; } bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
// Read an number of bytes from I2C uint8_t bcm2835_i2c_read(char* buf, uint32_t len) { #ifdef I2C_V1 volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; #endif uint32_t remaining = len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); // Set Data Length bcm2835_peri_write_nb(dlen, len); // Start read bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); // wait for transfer to complete while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { // we must empty the FIFO as it is populated and not use any delay while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) { // Read from FIFO, no barrier buf[i] = bcm2835_peri_read_nb(fifo); i++; remaining--; } } // transfer has finished - grab any remaining stuff in FIFO while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) { // Read from FIFO, no barrier buf[i] = bcm2835_peri_read_nb(fifo); i++; remaining--; } // Received a NACK if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { reason = BCM2835_I2C_REASON_ERROR_CLKT; } // Not all data is received else if (remaining) { reason = BCM2835_I2C_REASON_ERROR_DATA; } bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
// Writes an number of bytes to I2C uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) { #ifdef I2C_V1 volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; #endif uint32_t remaining = len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); // Set Data Length bcm2835_peri_write_nb(dlen, len); // pre populate FIFO with max buffer while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) { bcm2835_peri_write_nb(fifo, buf[i]); i++; remaining--; } // Enable device and start transfer bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); // Transfer is over when BCM2835_BSC_S_DONE while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE )) { while ( remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TXD )) { // Write to FIFO, no barrier bcm2835_peri_write_nb(fifo, buf[i]); i++; remaining--; } } // Received a NACK if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { reason = BCM2835_I2C_REASON_ERROR_CLKT; } // Not all data is sent else if (remaining) { reason = BCM2835_I2C_REASON_ERROR_DATA; } bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
// Writes (and reads) an number of bytes to SPI void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len, uint32_t delay) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t TXCnt=0; uint32_t RXCnt=0; uint32_t IGCnt = 0; uint32_t offset=0; uint32_t flip = 1; #if !SPI_GRAYONLY len -= 2*144; len *= 2; #endif // This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); #if SPI_TX // Use the FIFO's to reduce the interbyte times while((TXCnt < len)||(RXCnt < len)) { // TX fifo not full, so add some more bytes while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) { bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); TXCnt++; } #else /* Feed the dog before */ bcm2835_peri_write_nb(fifo, 0x00); bcm2835_peri_write_nb(fifo, 0x00); bcm2835_peri_write_nb(fifo, 0x00); int first = 4; while(RXCnt < len){ #endif //Rx fifo not empty, so get the next received bytes while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) { #if !SPI_TX bcm2835_peri_write_nb(fifo, 0x00); #endif #if TEX_W == 176 #if SPI_GRAYONLY if(!(RXCnt % 174)){ offset += 2; rbuf[RXCnt+offset-1] = 0xff; } #else if(flip && !(RXCnt % 174)){ offset += 2; } #endif #endif #if SPI_GRAYONLY rbuf[RXCnt + offset] = bcm2835_peri_read_nb(fifo); RXCnt++; #else /* Receiving full data, need to ignore UV values */ if(flip){ rbuf[RXCnt + offset] = bcm2835_peri_read_nb(fifo); RXCnt++; }else{ bcm2835_peri_read_nb(fifo); } flip ^= 1; #endif } usleep(delay); /* Let other threads do things */ } // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); //printf("Len: %d\t Rx: %d\tOffset: %d\tIg: %d\n", len, RXCnt, offset, IGCnt); //printf("%x %x %x\n", rbuf[RXCnt + offset - 3], rbuf[RXCnt + offset - 2], rbuf[RXCnt + offset - 1]); } // Writes an number of bytes to SPI void bcm2835_spi_writenb(char* tbuf, uint32_t len) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; // This is Polled transfer as per section 10.6.1 // BUG ALERT: what happens if we get interupted in this section, and someone else // accesses a different peripheral? // Clear TX and RX fifos bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); uint32_t i; for (i = 0; i < len; i++) { // Maybe wait for TXD while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO, no barrier bcm2835_peri_write_nb(fifo, tbuf[i]); // Read from FIFO to prevent stalling while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read_nb(fifo); } // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read_nb(fifo); }; // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); } // Writes (and reads) an number of bytes to SPI // Read bytes are copied over onto the transmit buffer void bcm2835_spi_transfern(char* buf, uint32_t len) { bcm2835_spi_transfernb(buf, buf, len, 0); }