/* * © 2021, Neil McKechnie. All rights reserved. * * This file is part of CommandStation-EX * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * It is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CommandStation. If not, see . */ #ifndef I2CMANAGER_SAMD_H #define I2CMANAGER_SAMD_H #include #include "I2CManager.h" //#include //#include #if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_SAMD_ZERO) // PMA - IRQ handler, based on SERCOM3 being used for I2C, as per Arduino Zero & Sparkfun SAMD21 // TODO: test void SERCOM3_Handler() { I2CManagerClass::handleInterrupt(); } #endif /*************************************************************************** * Set I2C clock speed register. ***************************************************************************/ void I2CManagerClass::I2C_setClock(unsigned long i2cClockSpeed) { unsigned long temp = ((F_CPU / i2cClockSpeed) - 16) / 2; for (uint8_t preScaler = 0; preScaler<=3; preScaler++) { if (temp <= 255) { TWBR = temp; TWSR = (TWSR & 0xfc) | preScaler; return; } else temp /= 4; } // Set slowest speed ~= 500 bits/sec TWBR = 255; TWSR |= 0x03; } /*************************************************************************** * Initialise I2C registers. ***************************************************************************/ void I2CManagerClass::I2C_init() { // PMA - broadly we do the following initialise the clock initialise the NVIC software reset the I2C for the sercom set master mode do we need smart mode and quick command?? configure interrupt handlers enable interrupts set default baud rate set SDA/SCL pins as outputs and enable pullups } /*************************************************************************** * Initiate a start bit for transmission. ***************************************************************************/ void I2CManagerClass::I2C_sendStart() { bytesToSend = currentRequest->writeLen; bytesToReceive = currentRequest->readLen; // We may have initiated a stop bit before this without waiting for it. // Wait for stop bit to be sent before sending start. while (TWCR & (1<writeBuffer + (txCount++)); else TWDR = currentRequest->writeBuffer[txCount++]; bytesToSend--; TWCR = (1< 0) { currentRequest->readBuffer[rxCount++] = TWDR; bytesToReceive--; } /* fallthrough */ case TWI_MRX_ADR_ACK: // SLA+R has been sent and ACK received if (bytesToReceive <= 1) { TWCR = (1< 0) { currentRequest->readBuffer[rxCount++] = TWDR; bytesToReceive--; } TWCR = (1<i2cAddress << 1) | 1; // SLA+R else TWDR = (currentRequest->i2cAddress << 1) | 0; // SLA+W TWCR = (1<