Browse Source

HAL_ChibiOS: added checking of bus owner

this ensures all bus transfers are only done by the thread that owns
the semaphore
master
Andrew Tridgell 7 years ago
parent
commit
f1ce321a2f
  1. 25
      libraries/AP_HAL_ChibiOS/I2CDevice.cpp
  2. 3
      libraries/AP_HAL_ChibiOS/SPIDevice.cpp
  3. 6
      libraries/AP_HAL_ChibiOS/Semaphores.h

25
libraries/AP_HAL_ChibiOS/I2CDevice.cpp

@ -126,6 +126,11 @@ void I2CBus::dma_deallocate(void) @@ -126,6 +126,11 @@ void I2CBus::dma_deallocate(void)
bool I2CDevice::transfer(const uint8_t *send, uint32_t send_len,
uint8_t *recv, uint32_t recv_len)
{
if (!bus.semaphore.check_owner()) {
hal.console->printf("ERR: I2C transfer by non-owner\n");
return false;
}
bus.dma_handle->lock();
if (_use_smbus) {
@ -172,41 +177,39 @@ bool I2CDevice::_transfer(const uint8_t *send, uint32_t send_len, @@ -172,41 +177,39 @@ bool I2CDevice::_transfer(const uint8_t *send, uint32_t send_len,
bus.bouncebuffer_setup(send_buf, send_len, recv_buf, recv_len);
i2cAcquireBus(I2CD[bus.busnum].i2c);
for(uint8_t i=0 ; i <= _retries; i++) {
int ret;
i2cAcquireBus(I2CD[bus.busnum].i2c);
// calculate a timeout as twice the expected transfer time, and set as min of 4ms
uint32_t timeout_ms = 1+2*(((8*1000000UL/bus.i2ccfg.clock_speed)*MAX(send_len, recv_len))/1000);
timeout_ms = MAX(timeout_ms, _timeout_ms);
bus.i2c_active = true;
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY, "i2cStart state");
if(send_len == 0) {
ret = i2cMasterReceiveTimeout(I2CD[bus.busnum].i2c, _address, recv_buf, recv_len, MS2ST(timeout_ms));
} else {
ret = i2cMasterTransmitTimeout(I2CD[bus.busnum].i2c, _address, send_buf, send_len,
recv_buf, recv_len, MS2ST(timeout_ms));
}
i2cReleaseBus(I2CD[bus.busnum].i2c);
bus.i2c_active = false;
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY, "i2cStart state");
if (ret != MSG_OK){
if (ret != MSG_OK) {
//restart the bus
if (bus.i2c_started) {
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY, "i2cStart state");
i2cStop(I2CD[bus.busnum].i2c);
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_STOP, "i2cStart state");
bus.i2c_started = false;
}
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY || I2CD[bus.busnum].i2c->state == I2C_LOCKED, "i2cStart state");
i2cStop(I2CD[bus.busnum].i2c);
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_STOP, "i2cStart state");
i2cStart(I2CD[bus.busnum].i2c, &bus.i2ccfg);
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY, "i2cStart state");
bus.i2c_started = true;
} else {
osalDbgAssert(I2CD[bus.busnum].i2c->state == I2C_READY, "i2cStart state");
if (recv_buf != recv) {
memcpy(recv, recv_buf, recv_len);
}
i2cReleaseBus(I2CD[bus.busnum].i2c);
return true;
}
}
i2cReleaseBus(I2CD[bus.busnum].i2c);
return false;
}

3
libraries/AP_HAL_ChibiOS/SPIDevice.cpp

@ -196,6 +196,7 @@ uint16_t SPIDevice::derive_freq_flag(uint32_t _frequency) @@ -196,6 +196,7 @@ uint16_t SPIDevice::derive_freq_flag(uint32_t _frequency)
bool SPIDevice::transfer(const uint8_t *send, uint32_t send_len,
uint8_t *recv, uint32_t recv_len)
{
bus.semaphore.assert_owner();
if (send_len == recv_len && send == recv) {
// simplest cases, needed for DMA
do_transfer(send, recv, recv_len);
@ -217,6 +218,7 @@ bool SPIDevice::transfer(const uint8_t *send, uint32_t send_len, @@ -217,6 +218,7 @@ bool SPIDevice::transfer(const uint8_t *send, uint32_t send_len,
bool SPIDevice::transfer_fullduplex(const uint8_t *send, uint8_t *recv, uint32_t len)
{
bus.semaphore.assert_owner();
uint8_t buf[len];
memcpy(buf, send, len);
do_transfer(buf, buf, len);
@ -245,6 +247,7 @@ bool SPIDevice::adjust_periodic_callback(AP_HAL::Device::PeriodicHandle h, uint3 @@ -245,6 +247,7 @@ bool SPIDevice::adjust_periodic_callback(AP_HAL::Device::PeriodicHandle h, uint3
*/
bool SPIDevice::set_chip_select(bool set)
{
bus.semaphore.assert_owner();
if (set && cs_forced) {
return true;
}

6
libraries/AP_HAL_ChibiOS/Semaphores.h

@ -29,6 +29,12 @@ public: @@ -29,6 +29,12 @@ public:
bool give();
bool take(uint32_t timeout_ms);
bool take_nonblocking();
bool check_owner(void) {
return _lock.owner == chThdGetSelfX();
}
void assert_owner(void) {
osalDbgAssert(check_owner(), "owner");
}
private:
mutex_t _lock;
};

Loading…
Cancel
Save