/* 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; }
int bcm2835_i2c_begin(void) { uint16_t cdiv; if ( bcm2835_bsc0 == MAP_FAILED || bcm2835_bsc1 == MAP_FAILED) return 0; /* bcm2835_init() failed, or not root */ #ifdef I2C_V1 volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ #else volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ #endif /* Read the clock divider register */ cdiv = bcm2835_peri_read(paddr); /* Calculate time for transmitting one byte // 1000000 = micros seconds in a second // 9 = Clocks per byte : 8 bits + ACK */ i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; return 1; }
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 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); }
// Read input pin static __inline__ uint8_t bcm2835_gpio_lev(uint8_t pin) { volatile uint32_t* paddr = gpio + BCM2835_GPLEV0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = bcm2835_peri_read(paddr); return (value & (1 << shift)) ? HIGH : LOW; }
/* See if an event detection bit is set // Sigh cant support interrupts yet */ uint8_t bcm2835_gpio_eds(uint8_t pin) { volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = bcm2835_peri_read(paddr); return (value & (1 << shift)) ? HIGH : LOW; }
//!>>>>>>>>>>>>>>>>> //!>>>>>>>>>>>>>>>>> //! Slave Select Lines must be toggled manually with this function extern void bcm2835_spi_write_prototype(char buf) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t i; uint32_t tempStoreVal; /* 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); { /* Maybe wait for TXD */ while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) // Wait until it can accept data ; /* Write to FIFO, WITH!!!!>>>> barrier */ bcm2835_peri_write(fifo, buf); // printf("\nFunction bcm2835_spi_write_prototype > FIFO: %02X\n", *fifo); /* Read from FIFO to prevent stalling */ while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) // Wait until transmission is completed (void) bcm2835_peri_read_nb(fifo); } /* Wait for DONE to be set */ while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_DONE)) { while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) (void) bcm2835_peri_read(fifo); // printf("\nFIFO - %zu\n", bcm2835_peri_read_nb(fifo)); }; printf("\nFunction bcm2835_spi_write_prototype > Write: %02X\n", buf); /* Set TA = 0, and also set the barrier */ // bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
/* 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); }
//uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr); /// Call bcm2835_peri_read_nb() with 1 parameter and set ope_code & return code on local buff /// \par Refer /// \par Modify /// \return done:0, time_over:-1 void ope_peri_read_nb(void) { uint32_t ret; get_int_code(); ret = bcm2835_peri_read( (volatile uint32_t *)(buff+5) ); set_ope_code( OPE_PERI_READ_NB ); set_int_code( ret ); put_reply(); mark_sync(); }
//uint32_t bcm2835_peri_read(volatile uint32_t* paddr); /// Call bcm2835_peri_read() with 1 parameter and set ope_code & return code on local buff /// \par Refer /// \par Modify /// \return done:0, time_over:-1 void ope_peri_read(void) { uint32_t ret; get_int_code(); ret = bcm2835_peri_read( (volatile uint32_t *)(buff+5) ); // buff:ope(1),ret(4),data set_ope_code( OPE_PERI_READ ); set_int_code( ret ); put_reply(); mark_sync(); }
/* 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); }
uint8_t bcm2835_spi_read_prototype(void) { volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint8_t testValue; testValue = bcm2835_peri_read(fifo); printf("\nFunction > bcm2835_spi_read_prototype Fifo: %08X\n", testValue); // return bcm2835_peri_read(fifo); return testValue; }
/* 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); }
void bcm2835_pwm_set_clock(uint32_t divisor) { // 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_i2c_begin(void) { volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; // Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL // Read the clock divider register uint16_t cdiv = bcm2835_peri_read(paddr); // Calculate time for transmitting one byte // 1000000 = micros seconds in a second // 9 = Clocks per byte : 8 bits + ACK i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; }
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); }
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 */ }
// 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); */ }
/* Set/clear only the bits in value covered by the mask * This is not atomic - can be interrupted. */ void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) { uint32_t v = bcm2835_peri_read(paddr); v = (v & ~mask) | (value & mask); bcm2835_peri_write(paddr, v); }
// 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); }
// Read GPIO pad behaviour for groups of GPIOs uint32_t bcm2835_gpio_pad(uint8_t group) { volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group*2; return bcm2835_peri_read(paddr); }
/* Read an number of bytes from I2C sending a repeated start after writing // the required register. Only works if your device supports this mode */ uint8_t bcm2835_i2c_read_register_rs(char* regaddr, 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(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); /* Set Data Length */ bcm2835_peri_write(dlen, 1); /* Enable device and start transfer */ bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); bcm2835_peri_write(fifo, regaddr[0]); bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); /* poll for transfer has started */ while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) { /* Linux may cause us to miss entire transfer stage */ if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) break; } /* Send a repeated start with read bit set in address */ bcm2835_peri_write(dlen, len); bcm2835_peri_write(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 * 3); /* wait for transfer to complete */ while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) { /* we must empty the FIFO as it is populated and not use any delay */ while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) { /* Read from FIFO */ buf[i] = bcm2835_peri_read(fifo); i++; remaining--; } } /* transfer has finished - grab any remaining stuff in FIFO */ while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) { /* Read from FIFO */ buf[i] = bcm2835_peri_read(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; }
// Set/clear only the bits in value covered by the mask void bcm2835_peri_set_bits(volatile u32 * paddr, u32 value, u32 mask) { u32 v = bcm2835_peri_read(paddr); v = (v & ~mask) | (value & mask); bcm2835_peri_write(paddr, v); }
uint32_t bcm2835_gpio_eds_multi(uint32_t mask) { volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; uint32_t value = bcm2835_peri_read(paddr); return (value & mask); }