2021-03-03 13:33:56 +00:00
|
|
|
/***************************************************************************
|
2025-04-04 17:06:57 +00:00
|
|
|
* Copyright (C) 2021 - 2025 by Federico Amedeo Izzo IU2NUO, *
|
2022-06-02 07:56:05 +00:00
|
|
|
* Niccolò Izzo IU2KIN *
|
|
|
|
* Frederik Saraci IU2NRO *
|
|
|
|
* Silvano Seva IU2KWO *
|
2021-03-03 13:33:56 +00:00
|
|
|
* *
|
|
|
|
* This program 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. *
|
|
|
|
* *
|
|
|
|
* This program 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 this program; if not, see <http://www.gnu.org/licenses/> *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2023-07-21 06:35:39 +00:00
|
|
|
#include <peripherals/gpio.h>
|
2021-03-03 13:33:56 +00:00
|
|
|
#include <interfaces/delays.h>
|
2021-04-15 08:03:17 +00:00
|
|
|
#include <hwconfig.h>
|
2021-03-03 13:33:56 +00:00
|
|
|
#include "AT1846S.h"
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void AT1846S::init()
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
i2c_writeReg16(0x30, 0x0001); // Soft reset
|
2021-03-20 10:50:39 +00:00
|
|
|
delayMs(160);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x30, 0x0004); // Set pdn_reg (power down pin)
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x04, 0x0FD0); // Set clk_mode to 25.6MHz/26MHz
|
|
|
|
i2c_writeReg16(0x0A, 0x7C20); // Set 0x0A to its default value
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x13, 0xA100);
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x1F, 0x1001); // Set gpio0 to ctcss_out/css_int/css_cmp
|
|
|
|
// and gpio6 to sq, sq&ctcss/cdcss when sq_out_set=1
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x31, 0x0031);
|
|
|
|
i2c_writeReg16(0x33, 0x44A5);
|
|
|
|
i2c_writeReg16(0x34, 0x2B89);
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x41, 0x4122); // Set voice_gain_tx (voice digital gain) to 0x22
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x42, 0x1052);
|
|
|
|
i2c_writeReg16(0x43, 0x0100);
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x44, 0x07FF); // Set gain_tx (voice digital gain after tx ADC downsample) to 0x7
|
|
|
|
i2c_writeReg16(0x59, 0x0B90); // Set c_dev (CTCSS/CDCSS TX FM deviation) to 0x10
|
|
|
|
// and xmitter_dev (voice/subaudio TX FM deviation) to 0x2E
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x47, 0x7F2F);
|
|
|
|
i2c_writeReg16(0x4F, 0x2C62);
|
|
|
|
i2c_writeReg16(0x53, 0x0094);
|
|
|
|
i2c_writeReg16(0x54, 0x2A3C);
|
|
|
|
i2c_writeReg16(0x55, 0x0081);
|
|
|
|
i2c_writeReg16(0x56, 0x0B02);
|
|
|
|
i2c_writeReg16(0x57, 0x1C00);
|
2022-08-02 10:54:51 +00:00
|
|
|
i2c_writeReg16(0x58, 0x9CDD); // Bit 0 = 1: CTCSS LPF bandwidth to 250Hz
|
|
|
|
// Bit 3 = 1: bypass CTCSS HPF
|
|
|
|
// Bit 4 = 1: bypass CTCSS LPF
|
|
|
|
// Bit 5 = 0: enable voice LPF
|
|
|
|
// Bit 6 = 1: bypass voice HPF
|
|
|
|
// Bit 7 = 1: bypass pre/de-emphasis
|
|
|
|
// Bit 11 = 1: bypass VOX HPF
|
|
|
|
// Bit 12 = 1: bypass VOX LPF
|
|
|
|
// Bit 13 = 0: normal RSSI LPF bandwidth
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x5A, 0x06DB);
|
|
|
|
i2c_writeReg16(0x63, 0x16AD);
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x67, 0x0628); // Set DTMF C0 697Hz to ???
|
|
|
|
i2c_writeReg16(0x68, 0x05E5); // Set DTMF C1 770Hz to 13MHz and 26MHz
|
|
|
|
i2c_writeReg16(0x69, 0x0555); // Set DTMF C2 852Hz to ???
|
|
|
|
i2c_writeReg16(0x6A, 0x04B8); // Set DTMF C3 941Hz to ???
|
|
|
|
i2c_writeReg16(0x6B, 0x02FE); // Set DTMF C4 1209Hz to 13MHz and 26MHz
|
|
|
|
i2c_writeReg16(0x6C, 0x01DD); // Set DTMF C5 1336Hz
|
|
|
|
i2c_writeReg16(0x6D, 0x00B1); // Set DTMF C6 1477Hz
|
|
|
|
i2c_writeReg16(0x6E, 0x0F82); // Set DTMF C7 1633Hz
|
|
|
|
i2c_writeReg16(0x6F, 0x017A); // Set DTMF C0 2nd harmonic
|
|
|
|
i2c_writeReg16(0x70, 0x004C); // Set DTMF C1 2nd harmonic
|
|
|
|
i2c_writeReg16(0x71, 0x0F1D); // Set DTMF C2 2nd harmonic
|
|
|
|
i2c_writeReg16(0x72, 0x0D91); // Set DTMF C3 2nd harmonic
|
|
|
|
i2c_writeReg16(0x73, 0x0A3E); // Set DTMF C4 2nd harmonic
|
|
|
|
i2c_writeReg16(0x74, 0x090F); // Set DTMF C5 2nd harmonic
|
|
|
|
i2c_writeReg16(0x75, 0x0833); // Set DTMF C6 2nd harmonic
|
|
|
|
i2c_writeReg16(0x76, 0x0806); // Set DTMF C7 2nd harmonic
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-03-18 22:13:46 +00:00
|
|
|
i2c_writeReg16(0x30, 0x40A4); // Set pdn_pin (power down enable)
|
|
|
|
// and set rx_on
|
|
|
|
// and set mute when rxno
|
|
|
|
// and set xtal_mode to 26MHz/13MHz
|
2021-03-20 10:50:39 +00:00
|
|
|
delayMs(160);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
i2c_writeReg16(0x30, 0x40A6); // Start calibration
|
2021-03-20 10:50:39 +00:00
|
|
|
delayMs(160);
|
2021-04-15 08:03:17 +00:00
|
|
|
i2c_writeReg16(0x30, 0x4006); // Stop calibration
|
2021-03-20 10:50:39 +00:00
|
|
|
delayMs(160);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
|
|
|
i2c_writeReg16(0x40, 0x0031);
|
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void AT1846S::setBandwidth(const AT1846S_BW band)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
if(band == AT1846S_BW::_25)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
// 25kHz bandwidth
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x15, 0x1F00);
|
|
|
|
i2c_writeReg16(0x32, 0x7564);
|
|
|
|
i2c_writeReg16(0x3A, 0x04C3);
|
|
|
|
i2c_writeReg16(0x3C, 0x1B34);
|
|
|
|
i2c_writeReg16(0x3F, 0x29D1);
|
|
|
|
i2c_writeReg16(0x48, 0x1F3C);
|
|
|
|
i2c_writeReg16(0x60, 0x0F17);
|
|
|
|
i2c_writeReg16(0x62, 0x3263);
|
|
|
|
i2c_writeReg16(0x65, 0x248A);
|
|
|
|
i2c_writeReg16(0x66, 0xFFAE);
|
|
|
|
i2c_writeReg16(0x7F, 0x0001);
|
|
|
|
i2c_writeReg16(0x06, 0x0024);
|
|
|
|
i2c_writeReg16(0x07, 0x0214);
|
|
|
|
i2c_writeReg16(0x08, 0x0224);
|
|
|
|
i2c_writeReg16(0x09, 0x0314);
|
|
|
|
i2c_writeReg16(0x0A, 0x0324);
|
|
|
|
i2c_writeReg16(0x0B, 0x0344);
|
|
|
|
i2c_writeReg16(0x0C, 0x0384);
|
|
|
|
i2c_writeReg16(0x0D, 0x1384);
|
|
|
|
i2c_writeReg16(0x0E, 0x1B84);
|
|
|
|
i2c_writeReg16(0x0F, 0x3F84);
|
|
|
|
i2c_writeReg16(0x12, 0xE0EB);
|
|
|
|
i2c_writeReg16(0x7F, 0x0000);
|
2021-04-15 08:03:17 +00:00
|
|
|
maskSetRegister(0x30, 0x3000, 0x3000);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
// 12.5kHz bandwidth
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x15, 0x1100);
|
|
|
|
i2c_writeReg16(0x32, 0x4495);
|
|
|
|
i2c_writeReg16(0x3A, 0x00C3);
|
|
|
|
i2c_writeReg16(0x3F, 0x29D1);
|
|
|
|
i2c_writeReg16(0x3C, 0x1B34);
|
|
|
|
i2c_writeReg16(0x48, 0x19B1);
|
|
|
|
i2c_writeReg16(0x60, 0x0F17);
|
|
|
|
i2c_writeReg16(0x62, 0x1425);
|
|
|
|
i2c_writeReg16(0x65, 0x2494);
|
|
|
|
i2c_writeReg16(0x66, 0xEB2E);
|
|
|
|
i2c_writeReg16(0x7F, 0x0001);
|
|
|
|
i2c_writeReg16(0x06, 0x0014);
|
|
|
|
i2c_writeReg16(0x07, 0x020C);
|
|
|
|
i2c_writeReg16(0x08, 0x0214);
|
|
|
|
i2c_writeReg16(0x09, 0x030C);
|
|
|
|
i2c_writeReg16(0x0A, 0x0314);
|
|
|
|
i2c_writeReg16(0x0B, 0x0324);
|
|
|
|
i2c_writeReg16(0x0C, 0x0344);
|
|
|
|
i2c_writeReg16(0x0D, 0x1344);
|
|
|
|
i2c_writeReg16(0x0E, 0x1B44);
|
|
|
|
i2c_writeReg16(0x0F, 0x3F44);
|
|
|
|
i2c_writeReg16(0x12, 0xE0EB);
|
|
|
|
i2c_writeReg16(0x7F, 0x0000);
|
2021-04-15 08:03:17 +00:00
|
|
|
maskSetRegister(0x30, 0x3000, 0x0000);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
reloadConfig();
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void AT1846S::setOpMode(const AT1846S_OpMode mode)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
if(mode == AT1846S_OpMode::DMR)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2022-05-31 16:19:57 +00:00
|
|
|
//
|
|
|
|
// TODO: values copy-pasted from GD77 driver, they seems to work well
|
|
|
|
// at least with M17
|
|
|
|
//
|
|
|
|
i2c_writeReg16(0x3A, 0x00C2);
|
|
|
|
i2c_writeReg16(0x33, 0x45F5);
|
|
|
|
i2c_writeReg16(0x41, 0x4731);
|
|
|
|
i2c_writeReg16(0x42, 0x1036);
|
|
|
|
i2c_writeReg16(0x43, 0x00BB);
|
2022-08-02 10:54:51 +00:00
|
|
|
i2c_writeReg16(0x58, 0xBCFD); // Bit 0 = 1: CTCSS LPF bandwidth to 250Hz
|
|
|
|
// Bit 3 = 1: bypass CTCSS HPF
|
|
|
|
// Bit 4 = 1: bypass CTCSS LPF
|
|
|
|
// Bit 5 = 1: bypass voice LPF
|
|
|
|
// Bit 6 = 1: bypass voice HPF
|
|
|
|
// Bit 7 = 1: bypass pre/de-emphasis
|
|
|
|
// Bit 11 = 1: bypass VOX HPF
|
|
|
|
// Bit 12 = 1: bypass VOX LPF
|
|
|
|
// Bit 13 = 1: bypass RSSI LPF
|
2022-05-31 16:19:57 +00:00
|
|
|
i2c_writeReg16(0x44, 0x06CC);
|
|
|
|
i2c_writeReg16(0x40, 0x0031);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
// FM mode
|
2022-08-02 10:54:51 +00:00
|
|
|
i2c_writeReg16(0x58, 0x9C05); // Bit 0 = 1: CTCSS LPF badwidth to 250Hz
|
|
|
|
// Bit 3 = 0: enable CTCSS HPF
|
|
|
|
// Bit 4 = 0: enable CTCSS LPF
|
|
|
|
// Bit 5 = 0: enable voice LPF
|
|
|
|
// Bit 6 = 0: enable voice HPF
|
|
|
|
// Bit 7 = 0: enable pre/de-emphasis
|
|
|
|
// Bit 11 = 1: bypass VOX HPF
|
|
|
|
// Bit 12 = 1: bypass VOX LPF
|
|
|
|
// Bit 13 = 0: normal RSSI LPF bandwidth
|
2021-03-03 13:33:56 +00:00
|
|
|
i2c_writeReg16(0x40, 0x0030);
|
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
reloadConfig();
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
/*
|
|
|
|
* Implementation of AT1846S I2C interface.
|
|
|
|
*
|
|
|
|
* On MD-UV3x0 the I2C interface towars the AT1846S is not connected to any
|
|
|
|
* hardware peripheral and has to be implemented in software by bit-banging.
|
|
|
|
*/
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void _i2c_start();
|
|
|
|
void _i2c_stop();
|
|
|
|
void _i2c_write(uint8_t val);
|
|
|
|
uint8_t _i2c_read(bool ack);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
static constexpr uint8_t devAddr = 0x5C;
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void AT1846S::i2c_init()
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setMode(I2C_SDA, INPUT);
|
|
|
|
gpio_setMode(I2C_SCL, OUTPUT);
|
|
|
|
gpio_clearPin(I2C_SCL);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void AT1846S::i2c_writeReg16(uint8_t reg, uint16_t value)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
/*
|
|
|
|
* Beware of endianness!
|
|
|
|
* When writing an AT1846S register, bits 15:8 must be sent first, followed
|
|
|
|
* by bits 7:0.
|
|
|
|
*/
|
|
|
|
uint8_t valHi = (value >> 8) & 0xFF;
|
|
|
|
uint8_t valLo = value & 0xFF;
|
|
|
|
|
|
|
|
_i2c_start();
|
|
|
|
_i2c_write(devAddr);
|
|
|
|
_i2c_write(reg);
|
|
|
|
_i2c_write(valHi);
|
|
|
|
_i2c_write(valLo);
|
|
|
|
_i2c_stop();
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
uint16_t AT1846S::i2c_readReg16(uint8_t reg)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
_i2c_start();
|
|
|
|
_i2c_write(devAddr);
|
|
|
|
_i2c_write(reg);
|
|
|
|
_i2c_start();
|
|
|
|
_i2c_write(devAddr | 0x01);
|
|
|
|
uint8_t valHi = _i2c_read(true);
|
|
|
|
uint8_t valLo = _i2c_read(false);
|
|
|
|
_i2c_stop();
|
|
|
|
|
|
|
|
return (valHi << 8) | valLo;
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
/*
|
|
|
|
* Software I2C routine
|
|
|
|
*/
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void _i2c_start()
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setMode(I2C_SDA, OUTPUT);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
/*
|
|
|
|
* Lines commented to keep SCL high when idle
|
|
|
|
*
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
*/
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setPin(I2C_SDA);
|
|
|
|
delayUs(2);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
2021-03-03 13:33:56 +00:00
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_clearPin(I2C_SDA);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(6);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void _i2c_stop()
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setMode(I2C_SDA, OUTPUT);
|
|
|
|
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
gpio_clearPin(I2C_SDA);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
gpio_setPin(I2C_SDA);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lines commented to keep SCL high when idle
|
|
|
|
*
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
*/
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
void _i2c_write(uint8_t val)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setMode(I2C_SDA, OUTPUT);
|
|
|
|
|
|
|
|
for(uint8_t i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(1);
|
|
|
|
|
|
|
|
if(val & 0x80)
|
|
|
|
{
|
|
|
|
gpio_setPin(I2C_SDA);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gpio_clearPin(I2C_SDA);
|
|
|
|
}
|
|
|
|
|
|
|
|
val <<= 1;
|
|
|
|
delayUs(1);
|
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure SCL is low before releasing SDA */
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
|
|
|
|
/* Clock cycle for slave ACK/NACK */
|
|
|
|
gpio_setMode(I2C_SDA, INPUT_PULL_UP);
|
|
|
|
delayUs(2);
|
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(1);
|
|
|
|
|
|
|
|
/* Asserting SDA pin allows to fastly bring the line to idle state */
|
|
|
|
gpio_setPin(I2C_SDA);
|
|
|
|
gpio_setMode(I2C_SDA, OUTPUT);
|
|
|
|
delayUs(6);
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 08:03:17 +00:00
|
|
|
uint8_t _i2c_read(bool ack)
|
2021-03-03 13:33:56 +00:00
|
|
|
{
|
2021-04-15 08:03:17 +00:00
|
|
|
gpio_setMode(I2C_SDA, INPUT_PULL_UP);
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
|
|
|
|
uint8_t value = 0;
|
|
|
|
for(uint8_t i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
delayUs(2);
|
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
value <<= 1;
|
|
|
|
value |= gpio_readPin(I2C_SDA);
|
|
|
|
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set ACK/NACK state BEFORE putting SDA gpio to output mode.
|
|
|
|
* This avoids spurious spikes which can be interpreted as NACKs
|
|
|
|
*/
|
|
|
|
gpio_clearPin(I2C_SDA);
|
|
|
|
gpio_setMode(I2C_SDA, OUTPUT);
|
|
|
|
delayUs(2);
|
|
|
|
if(!ack) gpio_setPin(I2C_SDA);
|
|
|
|
|
|
|
|
/* Clock cycle for ACK/NACK */
|
|
|
|
delayUs(2);
|
|
|
|
gpio_setPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
gpio_clearPin(I2C_SCL);
|
|
|
|
delayUs(2);
|
|
|
|
|
|
|
|
return value;
|
2021-03-03 13:33:56 +00:00
|
|
|
}
|