void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint8_t shift = 21 + cs; // Mask in the appropriate CSPOLn bit bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); }
// Async falling edge detect enable void bcm2835_gpio_afen(uint8_t pin) { uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = 1 << shift; bcm2835_peri_set_bits(paddr, value, value); }
void bcm2835_gpio_clr_hen(uint8_t pin) { volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = 1 << shift; bcm2835_peri_set_bits(paddr, 0, value); }
// 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; // 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); uint32_t i; for (i = 0; i < len; i++) { // 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, tbuf[i]); // Wait for RXD while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD)) delayMicroseconds(10); // then read the data byte rbuf[i] = bcm2835_peri_read_nb(fifo); } // Wait for DONE to be set while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) delayMicroseconds(10); // 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); }
void bcm2835_spi_Slave_Close_prototype(void) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; // Getting peripheral address of slave chosen so that we can send correct slave line // Close CS line // Set TA = 0, and also set the barrier bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) { /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); uint8_t shift = (pin % 10) * 3; uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; uint32_t value = mode << shift; bcm2835_peri_set_bits(paddr, value, mask); }
/* 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); }
/* * 2014年12月24日14:27:29 * V1.0 By Breaker * * int GPIO_SET_GPFSEL(int pin, int func) * 设置第pin个GPIO的功能(func) * return 0 成功 -1 失败 */ void GPIO_SET_GPFSEL(u8 pin, u8 mode) { //函数有错误 ,暂时不改 2015年02月08日18:59:50 //已解决 2015年03月11日18:56:25 // Function selects are 10 pins per 32 bit word, 3 bits per pin volatile u32 * paddr = ( volatile u32 * ) GPFSEL0 + (pin/10); u8 shift = (pin % 10) * 3; u32 mask = 0b111 << shift; // BCM2835_GPIO_FSEL_MASK = 0b111 u32 value = mode << shift; bcm2835_peri_set_bits(paddr, value, mask); }
// Function select // pin is a BCM2835 GPIO pin number NOT RPi pin number // There are 6 control registers, each control the functions of a block // of 10 pins. // Each control register has 10 sets of 3 bits per GPIO pin: // // 000 = GPIO Pin X is an input // 001 = GPIO Pin X is an output // 100 = GPIO Pin X takes alternate function 0 // 101 = GPIO Pin X takes alternate function 1 // 110 = GPIO Pin X takes alternate function 2 // 111 = GPIO Pin X takes alternate function 3 // 011 = GPIO Pin X takes alternate function 4 // 010 = GPIO Pin X takes alternate function 5 // // So the 3 bits for port X are: // X / 10 + ((X % 10) * 3) void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) { // Function selects are 10 pins per 32 bit word, 3 bits per pin volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); uint8_t shift = (pin % 10) * 3; uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; uint32_t value = mode << shift; DBG_MSG("%s:%s(%d) paddr=0x%08x, value=0x%08x, mask=0x%08x\n", __FILE__, __func__, __LINE__, paddr, value, mask); bcm2835_peri_set_bits(paddr, value, mask); }
void bcm2835_spi_Slave_Open_prototype(void) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; // Getting peripheral address of slave chosen so that we can send correct slave line // make sure cs close first // Clear Rx And Tx FIFOs buy sending "BCM2835_SPI0_CS_CLEAR" // bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_TA); // Memory Barrier set // Set CS = 1 or Slave = open bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, 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); }
//void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask); /// Call bcm2835_peri_set_bits with 3 parameter /// \par Refer /// \par Modify void ope_peri_set_bits(void) { volatile uint32_t* paddr; uint32_t value; uint32_t mask; get_int_code(); get_int_code(); get_int_code(); paddr = *((volatile uint32_t **)(buff+1)); value = *((volatile uint32_t *)(buff+5)); mask = *((volatile uint32_t *)(buff+9)); bcm2835_peri_set_bits( paddr, value, mask ); }
// 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) 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); printf("\nFunction > bcm2835_spi_transfer > Return Value: %d\n", ret); return ret; }
void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; // only valid for no custom CS if (cs <= BCM2835_SPI_CS_NONE) { uint8_t shift = 21 + cs; // Mask in the appropriate CSPOLn bit bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); } }
// 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_spi_slave_clear_fifo_prototype(void) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; // Getting peripheral address of slave chosen so that we can send correct slave line bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_TA); // Clear Rx And Tx FIFOs buy sending "BCM2835_SPI0_CS_CLEAR" }
void bcm2835_spi_chipSelect(uint8_t cs) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; /* Mask in the CS bits of CS */ bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); }
void bcm2835_spi_transfer_end() { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; /* Set TA = 0, and also set the barrier */ bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); }
void bcm2835_spi_setDataMode(uint8_t mode) { volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; /* Mask in the CPO and CPHA bits of CS */ bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); }
// 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 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; }