/* 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; }
// 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); }
// 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); }
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); }
// 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; }
/* 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; }
//!>>>>>>>>>>>>>>>>> //!>>>>>>>>>>>>>>>>> //! 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); }
// 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); }