mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 15:08:10 +01:00
Implement variable length single word SPI writes. (#5678)
This commit is contained in:
parent
dbdcb39af9
commit
2e6d01ddff
3 changed files with 46 additions and 14 deletions
|
@ -77,15 +77,19 @@ void SPIComponent::dump_config() {
|
||||||
|
|
||||||
void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
|
void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
|
||||||
|
|
||||||
uint8_t SPIDelegateBitBash::transfer(uint8_t data) {
|
uint8_t SPIDelegateBitBash::transfer(uint8_t data) { return this->transfer_(data, 8); }
|
||||||
|
|
||||||
|
void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_(data, num_bits); }
|
||||||
|
|
||||||
|
uint16_t SPIDelegateBitBash::transfer_(uint16_t data, size_t num_bits) {
|
||||||
// Clock starts out at idle level
|
// Clock starts out at idle level
|
||||||
this->clk_pin_->digital_write(clock_polarity_);
|
this->clk_pin_->digital_write(clock_polarity_);
|
||||||
uint8_t out_data = 0;
|
uint8_t out_data = 0;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i != num_bits; i++) {
|
||||||
uint8_t shift;
|
uint8_t shift;
|
||||||
if (bit_order_ == BIT_ORDER_MSB_FIRST) {
|
if (bit_order_ == BIT_ORDER_MSB_FIRST) {
|
||||||
shift = 7 - i;
|
shift = num_bits - 1 - i;
|
||||||
} else {
|
} else {
|
||||||
shift = i;
|
shift = i;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +98,7 @@ uint8_t SPIDelegateBitBash::transfer(uint8_t data) {
|
||||||
// sampling on leading edge
|
// sampling on leading edge
|
||||||
this->sdo_pin_->digital_write(data & (1 << shift));
|
this->sdo_pin_->digital_write(data & (1 << shift));
|
||||||
this->cycle_clock_();
|
this->cycle_clock_();
|
||||||
out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift;
|
out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
|
||||||
this->clk_pin_->digital_write(!this->clock_polarity_);
|
this->clk_pin_->digital_write(!this->clock_polarity_);
|
||||||
this->cycle_clock_();
|
this->cycle_clock_();
|
||||||
this->clk_pin_->digital_write(this->clock_polarity_);
|
this->clk_pin_->digital_write(this->clock_polarity_);
|
||||||
|
@ -104,7 +108,7 @@ uint8_t SPIDelegateBitBash::transfer(uint8_t data) {
|
||||||
this->clk_pin_->digital_write(!this->clock_polarity_);
|
this->clk_pin_->digital_write(!this->clock_polarity_);
|
||||||
this->sdo_pin_->digital_write(data & (1 << shift));
|
this->sdo_pin_->digital_write(data & (1 << shift));
|
||||||
this->cycle_clock_();
|
this->cycle_clock_();
|
||||||
out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift;
|
out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
|
||||||
this->clk_pin_->digital_write(this->clock_polarity_);
|
this->clk_pin_->digital_write(this->clock_polarity_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,15 @@ class SPIDelegate {
|
||||||
rxbuf[i] = this->transfer(txbuf[i]);
|
rxbuf[i] = this->transfer(txbuf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write a variable length data item, up to 16 bits.
|
||||||
|
* @param data The data to send. Should be LSB-aligned (i.e. top bits will be discarded.)
|
||||||
|
* @param num_bits The number of bits to send
|
||||||
|
*/
|
||||||
|
virtual void write(uint16_t data, size_t num_bits) {
|
||||||
|
esph_log_e("spi_device", "variable length write not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
// write 16 bits
|
// write 16 bits
|
||||||
virtual void write16(uint16_t data) {
|
virtual void write16(uint16_t data) {
|
||||||
if (this->bit_order_ == BIT_ORDER_MSB_FIRST) {
|
if (this->bit_order_ == BIT_ORDER_MSB_FIRST) {
|
||||||
|
@ -270,6 +279,10 @@ class SPIDelegateBitBash : public SPIDelegate {
|
||||||
|
|
||||||
uint8_t transfer(uint8_t data) override;
|
uint8_t transfer(uint8_t data) override;
|
||||||
|
|
||||||
|
void write(uint16_t data, size_t num_bits) override;
|
||||||
|
|
||||||
|
void write16(uint16_t data) override { this->write(data, 16); };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GPIOPin *clk_pin_;
|
GPIOPin *clk_pin_;
|
||||||
GPIOPin *sdo_pin_;
|
GPIOPin *sdo_pin_;
|
||||||
|
@ -284,6 +297,7 @@ class SPIDelegateBitBash : public SPIDelegate {
|
||||||
continue;
|
continue;
|
||||||
this->last_transition_ += this->wait_cycle_;
|
this->last_transition_ += this->wait_cycle_;
|
||||||
}
|
}
|
||||||
|
uint16_t transfer_(uint16_t data, size_t num_bits);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SPIBus {
|
class SPIBus {
|
||||||
|
@ -408,6 +422,8 @@ class SPIDevice : public SPIClient {
|
||||||
|
|
||||||
void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
|
void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
|
||||||
|
|
||||||
|
void write(uint16_t data, size_t num_bits) { this->delegate_->write(data, num_bits); };
|
||||||
|
|
||||||
void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); }
|
void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); }
|
||||||
|
|
||||||
void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); }
|
void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); }
|
||||||
|
|
|
@ -72,7 +72,11 @@ class SPIDelegateHw : public SPIDelegate {
|
||||||
desc.rxlength = this->write_only_ ? 0 : partial * 8;
|
desc.rxlength = this->write_only_ ? 0 : partial * 8;
|
||||||
desc.tx_buffer = txbuf;
|
desc.tx_buffer = txbuf;
|
||||||
desc.rx_buffer = rxbuf;
|
desc.rx_buffer = rxbuf;
|
||||||
esp_err_t const err = spi_device_transmit(this->handle_, &desc);
|
// polling is used as it has about 10% less overhead than queuing an interrupt transfer
|
||||||
|
esp_err_t err = spi_device_polling_start(this->handle_, &desc, portMAX_DELAY);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = spi_device_polling_end(this->handle_, portMAX_DELAY);
|
||||||
|
}
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Transmit failed - err %X", err);
|
ESP_LOGE(TAG, "Transmit failed - err %X", err);
|
||||||
break;
|
break;
|
||||||
|
@ -85,6 +89,21 @@ class SPIDelegateHw : public SPIDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write(uint16_t data, size_t num_bits) override {
|
||||||
|
spi_transaction_ext_t desc = {};
|
||||||
|
desc.command_bits = num_bits;
|
||||||
|
desc.base.flags = SPI_TRANS_VARIABLE_CMD;
|
||||||
|
desc.base.cmd = data;
|
||||||
|
esp_err_t err = spi_device_polling_start(this->handle_, (spi_transaction_t *) &desc, portMAX_DELAY);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = spi_device_polling_end(this->handle_, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Transmit failed - err %X", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void transfer(uint8_t *ptr, size_t length) override { this->transfer(ptr, ptr, length); }
|
void transfer(uint8_t *ptr, size_t length) override { this->transfer(ptr, ptr, length); }
|
||||||
|
|
||||||
uint8_t transfer(uint8_t data) override {
|
uint8_t transfer(uint8_t data) override {
|
||||||
|
@ -93,14 +112,7 @@ class SPIDelegateHw : public SPIDelegate {
|
||||||
return rxbuf;
|
return rxbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write16(uint16_t data) override {
|
void write16(uint16_t data) override { this->write(data, 16); }
|
||||||
if (this->bit_order_ == BIT_ORDER_MSB_FIRST) {
|
|
||||||
uint16_t txbuf = SPI_SWAP_DATA_TX(data, 16);
|
|
||||||
this->transfer((uint8_t *) &txbuf, nullptr, 2);
|
|
||||||
} else {
|
|
||||||
this->transfer((uint8_t *) &data, nullptr, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_array(const uint8_t *ptr, size_t length) override { this->transfer(ptr, nullptr, length); }
|
void write_array(const uint8_t *ptr, size_t length) override { this->transfer(ptr, nullptr, length); }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue