/** * @ingroup SPI * * Transfers any number of bytes to the currently selected SPI slave. * Asserts the currently selected CS pins (as previously set by \ref bcm2835_spi_chipSelect) * during the transfer. * * @param tbuf Buffer of bytes to send. * @param len Number of bytes in the tbuf buffer, and the number of bytes to send. */ void bcm2835_spi_writenb(const char* tbuf, const uint32_t len) { uint32_t i; // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); for (i = 0; i < len; i++) { // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO BCM2835_SPI0->FIFO = (uint32_t) tbuf[i]; while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } } // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) { while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } } // Set TA = 0 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
/** * * @param dmx_device_info */ static void ws2812_zero(dmx_device_info_t *dmx_device_info, const uint8_t *dmx_data) { int i,j; bcm2835_spi_setClockDivider((uint16_t) ((uint32_t) BCM2835_CORE_CLK_HZ / (uint32_t) 6400000)); bcm2835_spi_chipSelect(dmx_device_info->device_info.chip_select); // Just in case we have a multiplexer bcm2835_spi_setChipSelectPolarity(dmx_device_info->device_info.chip_select, LOW); // Just in case we have a multiplexer // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); for (i = 0; i < ((int) dmx_device_info->pixel_count * (int) WS2812_SLOTS_PER_PIXEL); i++) { for (j = 0; j < 8; j++) { // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; BCM2835_SPI0->FIFO = (uint32_t) WS2812_LOW_CODE; while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } } } // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) { while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } } // Set TA = 0 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
void bcm2835_spi_writenb(char* tbuf, uint32_t len) { // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); uint32_t i; for (i = 0; i < len; i++) { // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO, no barrier BCM2835_SPI0->FIFO = tbuf[i]; } // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0, and also set the barrier BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
void inline bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) { // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); uint32_t i; for (i = 0; i < len; i++) { // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO, no barrier //PUT32(BCM2835_SPI0_FIFO, tbuf[i]); BCM2835_SPI0->FIFO = tbuf[i]; // Wait for RXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) ; // then read the data byte rbuf[i] = BCM2835_SPI0->FIFO; } // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0, and also set the barrier BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
uint8_t bcm2835_i2c_read(char* buf, uint32_t len) { uint32_t remaining = len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO BCM2835_PERI_SET_BITS(BCM2835_BSC1->C, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status BCM2835_BSC1->S = BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE; // Set Data Length BCM2835_BSC1->DLEN = len; // Start read BCM2835_BSC1->C = BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ; // wait for transfer to complete while (!(BCM2835_BSC1->S & BCM2835_BSC_S_DONE)) { // we must empty the FIFO as it is populated and not use any delay while (BCM2835_BSC1->S & BCM2835_BSC_S_RXD) { // Read from FIFO, no barrier buf[i] = BCM2835_BSC1 ->FIFO; i++; remaining--; } } // transfer has finished - grab any remaining stuff in FIFO while (remaining && (BCM2835_BSC1 ->S & BCM2835_BSC_S_RXD)) { // Read from FIFO, no barrier buf[i] = BCM2835_BSC1 ->FIFO; i++; remaining--; } // Received a NACK if (BCM2835_BSC1 ->S & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (BCM2835_BSC1 ->S & 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(BCM2835_BSC1->C, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
/** * @ingroup DEV * * @param dmx_device_info */ static void ws2812(dmx_device_info_t * dmx_device_info, const uint8_t *dmx_data) { int i; uint8_t mask = 0x80; uint16_t dmx_data_index = dmx_device_info->dmx_start_address; bcm2835_spi_setClockDivider((uint16_t) ((uint32_t) BCM2835_CORE_CLK_HZ / (uint32_t) 6400000)); bcm2835_spi_chipSelect(dmx_device_info->device_info.chip_select); // Just in case we have a multiplexer bcm2835_spi_setChipSelectPolarity(dmx_device_info->device_info.chip_select, LOW); // Just in case we have a multiplexer // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); for (i = 0; i < ((int)dmx_device_info->pixel_count * (int)WS2812_SLOTS_PER_PIXEL); i++) { if (dmx_data_index > DMX_UNIVERSE_SIZE) { break; } mask = 0x80; while (mask != 0) { // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; if (dmx_data[dmx_data_index] & mask) { BCM2835_SPI0->FIFO = (uint32_t) WS2812_HIGH_CODE; } else { BCM2835_SPI0->FIFO = (uint32_t) WS2812_LOW_CODE; } while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } mask >>= 1; } dmx_data_index++; } // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) { while ((BCM2835_SPI0->CS & BCM2835_SPI0_CS_RXD)) { (void) BCM2835_SPI0->FIFO; } } // Set TA = 0 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) { uint32_t remaining = len; uint32_t i = 0; uint8_t reason = BCM2835_I2C_REASON_OK; // Clear FIFO BCM2835_PERI_SET_BITS(BCM2835_BSC1->C, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); // Clear Status BCM2835_BSC1->S = BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE; // Set Data Length BCM2835_BSC1->DLEN = len; // pre populate FIFO with max buffer while (remaining && (i < BCM2835_BSC_FIFO_SIZE)) { BCM2835_BSC1 ->FIFO = buf[i]; i++; remaining--; } // Enable device and start transfer BCM2835_BSC1->C = BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST; // Transfer is over when BCM2835_BSC_S_DONE while (!(BCM2835_BSC1 ->S & BCM2835_BSC_S_DONE)) { while (remaining && (BCM2835_BSC1 ->S & BCM2835_BSC_S_TXD)) { // Write to FIFO BCM2835_BSC1 ->FIFO = buf[i]; i++; remaining--; } } // Received a NACK if (BCM2835_BSC1 ->S & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; } // Received Clock Stretch Timeout else if (BCM2835_BSC1 ->S & 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(BCM2835_BSC1->C, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); return reason; }
/** * @ingroup SPI * * Transfers uint16_t (2 bytes) to the currently selected SPI slave. * Asserts the currently selected CS pins (as previously set by \ref bcm2835_spi_chipSelect) * during the transfer. * * @param data uint16_t */ void bcm2835_spi_write(const uint16_t data) { dsb(); // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO BCM2835_SPI0->FIFO = (uint32_t) data >> 8; BCM2835_SPI0->FIFO = (uint32_t) data & 0xFF; // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); dmb(); }
void inline bcm2835_spi_write(uint16_t data) { // Clear TX and RX fifos BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); // Set TA = 1 BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); // Maybe wait for TXD while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_TXD)) ; // Write to FIFO BCM2835_SPI0->FIFO = data >> 8; BCM2835_SPI0->FIFO = data & 0x0FF; // Wait for DONE to be set while (!(BCM2835_SPI0->CS & BCM2835_SPI0_CS_DONE)) ; // Set TA = 0, and also set the barrier BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, 0, BCM2835_SPI0_CS_TA); }
void inline bcm2835_spi_chipSelect(uint8_t cs) { BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, cs, BCM2835_SPI0_CS_CS); }
void inline bcm2835_spi_setDataMode(uint8_t mode) { // Mask in the CPO and CPHA bits of CS BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); }
void inline bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) { uint8_t shift = 21 + cs; // Mask in the appropriate CSPOLn bit BCM2835_PERI_SET_BITS(BCM2835_SPI0->CS, active << shift, 1 << shift); }