diff options
Diffstat (limited to 'shared-module/bitbangio')
| -rw-r--r-- | shared-module/bitbangio/I2C.c | 210 | ||||
| -rw-r--r-- | shared-module/bitbangio/SPI.c | 167 | ||||
| -rw-r--r-- | shared-module/bitbangio/__init__.c | 27 | ||||
| -rw-r--r-- | shared-module/bitbangio/types.h | 51 |
4 files changed, 455 insertions, 0 deletions
diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c new file mode 100644 index 000000000..bab5074b4 --- /dev/null +++ b/shared-module/bitbangio/I2C.c @@ -0,0 +1,210 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George, Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/bitbangio/I2C.h" + +#include "py/obj.h" + +#include "common-hal/microcontroller/types.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/nativeio/DigitalInOut.h" +#include "shared-module/bitbangio/types.h" + +#define I2C_STRETCH_LIMIT 255 + +STATIC void delay(bitbangio_i2c_obj_t *self) { + // We need to use an accurate delay to get acceptable I2C + // speeds (eg 1us should be not much more than 1us). + common_hal_mcu_delay_us(self->us_delay); +} + +STATIC void scl_low(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_set_value(&self->scl, false); +} + +STATIC void scl_release(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_set_value(&self->scl, true); + delay(self); + // For clock stretching, wait for the SCL pin to be released, with timeout. + for (int count = I2C_STRETCH_LIMIT; !common_hal_nativeio_digitalinout_get_value(&self->scl) && count; --count) { + common_hal_mcu_delay_us(1); + } +} + +STATIC void sda_low(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_set_value(&self->sda, false); +} + +STATIC void sda_release(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_set_value(&self->sda, true); +} + +STATIC bool sda_read(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_switch_to_input(&self->sda, PULL_UP); + bool value = common_hal_nativeio_digitalinout_get_value(&self->sda); + common_hal_nativeio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); + return value; +} + +STATIC void start(bitbangio_i2c_obj_t *self) { + sda_release(self); + delay(self); + scl_release(self); + sda_low(self); + delay(self); +} + +STATIC void stop(bitbangio_i2c_obj_t *self) { + delay(self); + sda_low(self); + delay(self); + scl_release(self); + sda_release(self); + delay(self); +} + +STATIC int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { + delay(self); + scl_low(self); + + for (int i = 7; i >= 0; i--) { + if ((val >> i) & 1) { + sda_release(self); + } else { + sda_low(self); + } + delay(self); + scl_release(self); + scl_low(self); + } + + sda_release(self); + delay(self); + scl_release(self); + + int ret = sda_read(self); + delay(self); + scl_low(self); + + return !ret; +} + +STATIC bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { + delay(self); + scl_low(self); + delay(self); + + uint8_t data = 0; + for (int i = 7; i >= 0; i--) { + scl_release(self); + data = (data << 1) | sda_read(self); + scl_low(self); + delay(self); + } + *val = data; + + // send ack/nack bit + if (ack) { + sda_low(self); + } + delay(self); + scl_release(self); + scl_low(self); + sda_release(self); + + return true; +} + +void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, + const mcu_pin_obj_t * scl, + const mcu_pin_obj_t * sda, + uint32_t freq) { + self->us_delay = 500000 / freq; + if (self->us_delay == 0) { + self->us_delay = 1; + } + digitalinout_result_t result = common_hal_nativeio_digitalinout_construct(&self->scl, scl); + if (result != DIGITALINOUT_OK) { + return; + } + result = common_hal_nativeio_digitalinout_construct(&self->sda, sda); + if (result != DIGITALINOUT_OK) { + common_hal_nativeio_digitalinout_deinit(&self->scl); + return; + } + common_hal_nativeio_digitalinout_switch_to_output(&self->scl, true, DRIVE_MODE_OPEN_DRAIN); + common_hal_nativeio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); + + stop(self); +} + +void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self) { + common_hal_nativeio_digitalinout_deinit(&self->scl); + common_hal_nativeio_digitalinout_deinit(&self->sda); +} + +bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr) { + start(self); + bool ok = write_byte(self, addr << 1); + stop(self); + return ok; +} + +bool shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len, bool transmit_stop_bit) { + // start the I2C transaction + start(self); + bool ok = write_byte(self, addr << 1); + + for (uint32_t i = 0; i < len; i++) { + ok = ok && write_byte(self, data[i]); + if (!ok) { + break; + } + } + + if (transmit_stop_bit) { + stop(self); + } + return ok; +} + +bool shared_module_bitbangio_i2c_read(bitbangio_i2c_obj_t *self, uint16_t addr, + uint8_t * data, size_t len) { + // start the I2C transaction + start(self); + bool ok = write_byte(self, (addr << 1) | 1); + + for (uint32_t i = 0; i < len; i++) { + ok = ok && read_byte(self, data + i, i < len - 1); + if (!ok) { + break; + } + } + + stop(self); + return ok; +} diff --git a/shared-module/bitbangio/SPI.c b/shared-module/bitbangio/SPI.c new file mode 100644 index 000000000..5d77efaf9 --- /dev/null +++ b/shared-module/bitbangio/SPI.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "mpconfigport.h" + +#include "py/obj.h" + +#include "common-hal/microcontroller/types.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/nativeio/DigitalInOut.h" +#include "shared-module/bitbangio/types.h" + +#define MAX_BAUDRATE (common_hal_mcu_get_clock_frequency() / 48) + +extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, + const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso, uint32_t baudrate) { + digitalinout_result_t result = common_hal_nativeio_digitalinout_construct(&self->clock, clock); + if (result != DIGITALINOUT_OK) { + return; + } + result = common_hal_nativeio_digitalinout_construct(&self->mosi, mosi); + if (result != DIGITALINOUT_OK) { + common_hal_nativeio_digitalinout_deinit(&self->clock); + return; + } + result = common_hal_nativeio_digitalinout_construct(&self->miso, miso); + if (result != DIGITALINOUT_OK) { + common_hal_nativeio_digitalinout_deinit(&self->clock); + common_hal_nativeio_digitalinout_deinit(&self->mosi); + return; + } + + self->delay_half = 500000 / baudrate; + // round delay_half up so that: actual_baudrate <= requested_baudrate + if (500000 % baudrate != 0) { + self->delay_half += 1; + } + + self->polarity = 0; + self->phase = 0; +} + +extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) { + common_hal_nativeio_digitalinout_deinit(&self->clock); + common_hal_nativeio_digitalinout_deinit(&self->mosi); + common_hal_nativeio_digitalinout_deinit(&self->miso); +} + +bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, + const uint8_t *write_buffer, size_t write_buffer_len, + uint8_t *read_buffer, size_t read_buffer_len) { + uint32_t delay_half = self->delay_half; + + // only MSB transfer is implemented + + // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY + if (delay_half <= MICROPY_PY_MACHINE_SPI_MIN_DELAY) { + for (size_t i = 0; i < write_buffer_len; ++i) { + uint8_t data_out = write_buffer[i]; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + common_hal_nativeio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + + // Clock out zeroes while we read. + common_hal_nativeio_digitalinout_set_value(&self->mosi, false); + for (size_t i = 0; i < read_buffer_len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + data_in = (data_in << 1) | common_hal_nativeio_digitalinout_get_value(&self->miso); + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + } + read_buffer[i] = data_in; + } + return true; + } + #endif + + for (size_t i = 0; i < write_buffer_len; ++i) { + uint8_t data_out = write_buffer[i]; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + common_hal_nativeio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + common_hal_mcu_delay_us(delay_half); + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + } else { + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + common_hal_mcu_delay_us(delay_half); + } + if (self->phase == 0) { + common_hal_mcu_delay_us(delay_half); + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + } else { + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + common_hal_mcu_delay_us(delay_half); + } + } + + // Some ports need a regular callback, but probably we don't need + // to do this every byte, or even at all. + #ifdef MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK; + #endif + } + common_hal_nativeio_digitalinout_set_value(&self->mosi, false); + for (size_t i = 0; i < read_buffer_len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j) { + if (self->phase == 0) { + common_hal_mcu_delay_us(delay_half); + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + } else { + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + common_hal_mcu_delay_us(delay_half); + } + data_in = (data_in << 1) | common_hal_nativeio_digitalinout_get_value(&self->miso); + if (self->phase == 0) { + common_hal_mcu_delay_us(delay_half); + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + } else { + common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); + common_hal_mcu_delay_us(delay_half); + } + } + read_buffer[i] = data_in; + + // Some ports need a regular callback, but probably we don't need + // to do this every byte, or even at all. + #ifdef MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK; + #endif + } + return true; +} diff --git a/shared-module/bitbangio/__init__.c b/shared-module/bitbangio/__init__.c new file mode 100644 index 000000000..674343c53 --- /dev/null +++ b/shared-module/bitbangio/__init__.c @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Nothing now. diff --git a/shared-module/bitbangio/types.h b/shared-module/bitbangio/types.h new file mode 100644 index 000000000..e6a29ab54 --- /dev/null +++ b/shared-module/bitbangio/types.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H__ +#define __MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H__ + +#include "common-hal/nativeio/types.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + nativeio_digitalinout_obj_t scl; + nativeio_digitalinout_obj_t sda; + uint32_t us_delay; +} bitbangio_i2c_obj_t; + +typedef struct { + mp_obj_base_t base; + nativeio_digitalinout_obj_t clock; + nativeio_digitalinout_obj_t mosi; + nativeio_digitalinout_obj_t miso; + uint32_t delay_half; + uint8_t polarity; + uint8_t phase; +} bitbangio_spi_obj_t; + +#endif // __MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H__ |
