kopia lustrzana https://github.com/solokeys/solo1
NFC capability started
rodzic
bfd14ec6bf
commit
58ec4b16c5
File diff suppressed because one or more lines are too long
|
@ -3,7 +3,7 @@
|
|||
<mode name="DefaultMode">
|
||||
<property object="ADC0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="clocksettings.hfrcosettings.hfrcofrequency" value="38 MHz"/>
|
||||
<property object="CMU" propertyId="clocksettings.hfrcosettings.hfrcofrequency" value="13 MHz"/>
|
||||
<property object="CMU" propertyId="clocksettings.lfclocksettings.lfrcorequired" value="Yes"/>
|
||||
<property object="CRYOTIMER" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CRYOTIMER" propertyId="cryotimer.clocking.eventafterevery" value="1 cycle"/>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<property object="DefaultMode" propertyId="mode.diagramLocation" value="100, 100"/>
|
||||
<property object="EMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="GPIO" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="LDMA" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="I2C0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="PA0" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PA1" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PA1" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
|
@ -20,6 +20,7 @@
|
|||
<property object="PA1" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PA1" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PA3" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PA4" propertyId="ports.settings.pinmode" value="Wired-and pullup filter"/>
|
||||
<property object="PA5" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PA5" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PA5" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
|
@ -60,6 +61,7 @@
|
|||
<property object="PD10" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD10" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD10" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PF3" propertyId="ports.settings.pinmode" value="Wired-and pullup filter"/>
|
||||
<property object="PF4" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PF5" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PF6" propertyId="ports.settings.dout" value="1"/>
|
||||
|
@ -67,6 +69,10 @@
|
|||
<property object="PF6" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PF6" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PF6" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.enable.scl" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.enable.sda" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.location.i2c0_sclloc" value="3"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.location.i2c0_sdaloc" value="27"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.cts" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.rts" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.rx" value="Enabled"/>
|
||||
|
|
|
@ -0,0 +1,811 @@
|
|||
/***************************************************************************//**
|
||||
* @file em_i2c.c
|
||||
* @brief Inter-integrated Circuit (I2C) Peripheral API
|
||||
* @version 5.2.2
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
|
||||
* obligation to support this Software. Silicon Labs is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Silicon Labs will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "em_i2c.h"
|
||||
#if defined(I2C_COUNT) && (I2C_COUNT > 0)
|
||||
|
||||
#include "em_cmu.h"
|
||||
#include "em_bus.h"
|
||||
#include "em_assert.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup emlib
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup I2C
|
||||
* @brief Inter-integrated Circuit (I2C) Peripheral API
|
||||
* @details
|
||||
* This module contains functions to control the I2C peripheral of Silicon
|
||||
* Labs 32-bit MCUs and SoCs. The I2C interface allows communication on I2C
|
||||
* buses with the lowest energy consumption possible.
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* DEFINES ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
/** Validation of I2C register block pointer reference for assert statements. */
|
||||
#if (I2C_COUNT == 1)
|
||||
#define I2C_REF_VALID(ref) ((ref) == I2C0)
|
||||
#elif (I2C_COUNT == 2)
|
||||
#define I2C_REF_VALID(ref) ((ref == I2C0) || (ref == I2C1))
|
||||
#elif (I2C_COUNT == 3)
|
||||
#define I2C_REF_VALID(ref) ((ref == I2C0) || (ref == I2C1) || (ref == I2C2))
|
||||
#endif
|
||||
|
||||
/** Error flags indicating I2C transfer has failed somehow. */
|
||||
/* Notice that I2C_IF_TXOF (transmit overflow) is not really possible with */
|
||||
/* this SW supporting master mode. Likewise for I2C_IF_RXUF (receive underflow) */
|
||||
/* RXUF is only likely to occur with this SW if using a debugger peeking into */
|
||||
/* RXDATA register. Thus, we ignore those types of fault. */
|
||||
#define I2C_IF_ERRORS (I2C_IF_BUSERR | I2C_IF_ARBLOST)
|
||||
|
||||
/* Max I2C transmission rate constant */
|
||||
#if defined(_SILICON_LABS_32B_SERIES_0)
|
||||
#define I2C_CR_MAX 4
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_1)
|
||||
#define I2C_CR_MAX 8
|
||||
#else
|
||||
#warning "Max I2C transmission rate constant is not defined"
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*******************************************************************************
|
||||
******************************** ENUMS ************************************
|
||||
******************************************************************************/
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
/** Master mode transfer states. */
|
||||
typedef enum {
|
||||
i2cStateStartAddrSend, /**< Send start + (first part of) address. */
|
||||
i2cStateAddrWFAckNack, /**< Wait for ACK/NACK on (first part of) address. */
|
||||
i2cStateAddrWF2ndAckNack, /**< Wait for ACK/NACK on second part of 10 bit address. */
|
||||
i2cStateRStartAddrSend, /**< Send repeated start + (first part of) address. */
|
||||
i2cStateRAddrWFAckNack, /**< Wait for ACK/NACK on address sent after repeated start. */
|
||||
i2cStateDataSend, /**< Send data. */
|
||||
i2cStateDataWFAckNack, /**< Wait for ACK/NACK on data sent. */
|
||||
i2cStateWFData, /**< Wait for data. */
|
||||
i2cStateWFStopSent, /**< Wait for STOP to have been transmitted. */
|
||||
i2cStateDone /**< Transfer completed successfully. */
|
||||
} I2C_TransferState_TypeDef;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* STRUCTS ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
/** Structure used to store state information on an ongoing master mode transfer. */
|
||||
typedef struct {
|
||||
/** Current state. */
|
||||
I2C_TransferState_TypeDef state;
|
||||
|
||||
/** Result return code. */
|
||||
I2C_TransferReturn_TypeDef result;
|
||||
|
||||
/** Offset in current sequence buffer. */
|
||||
uint16_t offset;
|
||||
|
||||
/* Index to current sequence buffer in use. */
|
||||
uint8_t bufIndx;
|
||||
|
||||
/** Reference to I2C transfer sequence definition provided by user. */
|
||||
I2C_TransferSeq_TypeDef *seq;
|
||||
} I2C_Transfer_TypeDef;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** LOCAL DATA *******^**************************
|
||||
******************************************************************************/
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
/**
|
||||
* Lookup table for Nlow + Nhigh setting defined by CLHR. Set undefined
|
||||
* index (0x3) to reflect default setting just in case.
|
||||
*/
|
||||
static const uint8_t i2cNSum[] = { 4 + 4, 6 + 3, 11 + 6, 4 + 4 };
|
||||
|
||||
/** Transfer state info for ongoing master mode transfer */
|
||||
static I2C_Transfer_TypeDef i2cTransfer[I2C_COUNT];
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get current configured I2C bus frequency.
|
||||
*
|
||||
* @details
|
||||
* This frequency is only of relevance when acting as master.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @return
|
||||
* Current I2C frequency in Hz.
|
||||
******************************************************************************/
|
||||
uint32_t I2C_BusFreqGet(I2C_TypeDef *i2c)
|
||||
{
|
||||
uint32_t freqHfper;
|
||||
uint32_t n;
|
||||
|
||||
/* Max frequency is given by freqScl = freqHfper/((Nlow + Nhigh)(DIV + 1) + I2C_CR_MAX)
|
||||
* More details can be found in the reference manual,
|
||||
* I2C Clock Generation chapter. */
|
||||
freqHfper = CMU_ClockFreqGet(cmuClock_HFPER);
|
||||
/* n = Nlow + Nhigh */
|
||||
n = (uint32_t)(i2cNSum[(i2c->CTRL & _I2C_CTRL_CLHR_MASK) >> _I2C_CTRL_CLHR_SHIFT]);
|
||||
|
||||
return (freqHfper / ((n * (i2c->CLKDIV + 1)) + I2C_CR_MAX));
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set I2C bus frequency.
|
||||
*
|
||||
* @details
|
||||
* The bus frequency is only of relevance when acting as a master. The bus
|
||||
* frequency should not be set higher than the max frequency accepted by the
|
||||
* slowest device on the bus.
|
||||
*
|
||||
* Notice that due to asymmetric requirements on low and high I2C clock
|
||||
* cycles by the I2C specification, the actual max frequency allowed in order
|
||||
* to comply with the specification may be somewhat lower than expected.
|
||||
*
|
||||
* Please refer to the reference manual, details on I2C clock generation,
|
||||
* for max allowed theoretical frequencies for different modes.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @param[in] freqRef
|
||||
* I2C reference clock frequency in Hz that will be used. If set to 0,
|
||||
* then HFPER clock is used. Setting it to a higher than actual configured
|
||||
* value only has the consequence of reducing the real I2C frequency.
|
||||
*
|
||||
* @param[in] freqScl
|
||||
* Bus frequency to set (actual bus speed may be lower due to integer
|
||||
* prescaling). Safe (according to I2C specification) max frequencies for
|
||||
* standard, fast and fast+ modes are available using I2C_FREQ_ defines.
|
||||
* (Using I2C_FREQ_ defines requires corresponding setting of @p type.)
|
||||
* Slowest slave device on bus must always be considered.
|
||||
*
|
||||
* @param[in] i2cMode
|
||||
* Clock low to high ratio type to use. If not using i2cClockHLRStandard,
|
||||
* make sure all devices on the bus support the specified mode. Using a
|
||||
* non-standard ratio is useful to achieve higher bus clock in fast and
|
||||
* fast+ modes.
|
||||
******************************************************************************/
|
||||
void I2C_BusFreqSet(I2C_TypeDef *i2c,
|
||||
uint32_t freqRef,
|
||||
uint32_t freqScl,
|
||||
I2C_ClockHLR_TypeDef i2cMode)
|
||||
{
|
||||
uint32_t n, minFreq;
|
||||
int32_t div;
|
||||
|
||||
/* Avoid divide by 0 */
|
||||
EFM_ASSERT(freqScl);
|
||||
if (!freqScl) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the CLHR (clock low to high ratio). */
|
||||
i2c->CTRL &= ~_I2C_CTRL_CLHR_MASK;
|
||||
BUS_RegMaskedWrite(&i2c->CTRL,
|
||||
_I2C_CTRL_CLHR_MASK,
|
||||
i2cMode << _I2C_CTRL_CLHR_SHIFT);
|
||||
|
||||
if (!freqRef) {
|
||||
freqRef = CMU_ClockFreqGet(cmuClock_HFPER);
|
||||
}
|
||||
|
||||
/* Check minumum HF peripheral clock */
|
||||
minFreq = UINT_MAX;
|
||||
if (i2c->CTRL & I2C_CTRL_SLAVE) {
|
||||
switch (i2cMode) {
|
||||
case i2cClockHLRStandard:
|
||||
#if defined(_SILICON_LABS_32B_SERIES_0)
|
||||
minFreq = 4200000; break;
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_1)
|
||||
minFreq = 2000000; break;
|
||||
#endif
|
||||
case i2cClockHLRAsymetric:
|
||||
#if defined(_SILICON_LABS_32B_SERIES_0)
|
||||
minFreq = 11000000; break;
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_1)
|
||||
minFreq = 5000000; break;
|
||||
#endif
|
||||
case i2cClockHLRFast:
|
||||
#if defined(_SILICON_LABS_32B_SERIES_0)
|
||||
minFreq = 24400000; break;
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_1)
|
||||
minFreq = 14000000; break;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* For master mode, platform 1 and 2 share the same
|
||||
min frequencies */
|
||||
switch (i2cMode) {
|
||||
case i2cClockHLRStandard:
|
||||
minFreq = 2000000; break;
|
||||
case i2cClockHLRAsymetric:
|
||||
minFreq = 9000000; break;
|
||||
case i2cClockHLRFast:
|
||||
minFreq = 20000000; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Frequency most be larger-than */
|
||||
EFM_ASSERT(freqRef > minFreq);
|
||||
|
||||
/* SCL frequency is given by
|
||||
* freqScl = freqRef/((Nlow + Nhigh) * (DIV + 1) + I2C_CR_MAX)
|
||||
*
|
||||
* Thus
|
||||
* DIV = ((freqRef - (I2C_CR_MAX * freqScl))/((Nlow + Nhigh) * freqScl)) - 1
|
||||
*
|
||||
* More details can be found in the reference manual,
|
||||
* I2C Clock Generation chapter. */
|
||||
|
||||
/* n = Nlow + Nhigh */
|
||||
n = (uint32_t)(i2cNSum[i2cMode]);
|
||||
div = ((freqRef - (I2C_CR_MAX * freqScl)) / (n * freqScl)) - 1;
|
||||
EFM_ASSERT(div >= 0);
|
||||
EFM_ASSERT((uint32_t)div <= _I2C_CLKDIV_DIV_MASK);
|
||||
|
||||
/* Clock divisor must be at least 1 in slave mode according to reference */
|
||||
/* manual (in which case there is normally no need to set bus frequency). */
|
||||
if ((i2c->CTRL & I2C_CTRL_SLAVE) && !div) {
|
||||
div = 1;
|
||||
}
|
||||
i2c->CLKDIV = (uint32_t)div;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable/disable I2C.
|
||||
*
|
||||
* @note
|
||||
* After enabling the I2C (from being disabled), the I2C is in BUSY state.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @param[in] enable
|
||||
* true to enable counting, false to disable.
|
||||
******************************************************************************/
|
||||
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
|
||||
{
|
||||
EFM_ASSERT(I2C_REF_VALID(i2c));
|
||||
|
||||
BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, enable);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Initialize I2C.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @param[in] init
|
||||
* Pointer to I2C initialization structure.
|
||||
******************************************************************************/
|
||||
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init)
|
||||
{
|
||||
EFM_ASSERT(I2C_REF_VALID(i2c));
|
||||
|
||||
i2c->IEN = 0;
|
||||
i2c->IFC = _I2C_IFC_MASK;
|
||||
|
||||
/* Set SLAVE select mode */
|
||||
BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_SLAVE_SHIFT, init->master ? 0 : 1);
|
||||
|
||||
I2C_BusFreqSet(i2c, init->refFreq, init->freq, init->clhr);
|
||||
|
||||
BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, init->enable);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Reset I2C to same state as after a HW reset.
|
||||
*
|
||||
* @note
|
||||
* The ROUTE register is NOT reset by this function, in order to allow for
|
||||
* centralized setup of this feature.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
******************************************************************************/
|
||||
void I2C_Reset(I2C_TypeDef *i2c)
|
||||
{
|
||||
i2c->CTRL = _I2C_CTRL_RESETVALUE;
|
||||
i2c->CLKDIV = _I2C_CLKDIV_RESETVALUE;
|
||||
i2c->SADDR = _I2C_SADDR_RESETVALUE;
|
||||
i2c->SADDRMASK = _I2C_SADDRMASK_RESETVALUE;
|
||||
i2c->IEN = _I2C_IEN_RESETVALUE;
|
||||
i2c->IFC = _I2C_IFC_MASK;
|
||||
/* Do not reset route register, setting should be done independently */
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Continue an initiated I2C transfer (single master mode only).
|
||||
*
|
||||
* @details
|
||||
* This function is used repeatedly after a I2C_TransferInit() in order to
|
||||
* complete a transfer. It may be used in polled mode as the below example
|
||||
* shows:
|
||||
* @verbatim
|
||||
* I2C_TransferReturn_TypeDef ret;
|
||||
*
|
||||
* // Do a polled transfer
|
||||
* ret = I2C_TransferInit(I2C0, seq);
|
||||
* while (ret == i2cTransferInProgress)
|
||||
* {
|
||||
* ret = I2C_Transfer(I2C0);
|
||||
* }
|
||||
* @endverbatim
|
||||
* It may also be used in interrupt driven mode, where this function is invoked
|
||||
* from the interrupt handler. Notice that if used in interrupt mode, NVIC
|
||||
* interrupts must be configured and enabled for the I2C bus used. I2C
|
||||
* peripheral specific interrupts are managed by this SW.
|
||||
*
|
||||
* @note
|
||||
* Only single master mode is supported.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @return
|
||||
* Returns status for ongoing transfer.
|
||||
* @li #i2cTransferInProgress - indicates that transfer not finished.
|
||||
* @li #i2cTransferDone - transfer completed successfully.
|
||||
* @li otherwise some sort of error has occurred.
|
||||
*
|
||||
******************************************************************************/
|
||||
I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c)
|
||||
{
|
||||
uint32_t tmp;
|
||||
uint32_t pending;
|
||||
I2C_Transfer_TypeDef *transfer;
|
||||
I2C_TransferSeq_TypeDef *seq;
|
||||
|
||||
EFM_ASSERT(I2C_REF_VALID(i2c));
|
||||
|
||||
/* Support up to 2 I2C buses */
|
||||
if (i2c == I2C0) {
|
||||
transfer = i2cTransfer;
|
||||
}
|
||||
#if (I2C_COUNT > 1)
|
||||
else if (i2c == I2C1) {
|
||||
transfer = i2cTransfer + 1;
|
||||
}
|
||||
#endif
|
||||
#if (I2C_COUNT > 2)
|
||||
else if (i2c == I2C2) {
|
||||
transfer = i2cTransfer + 2;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return i2cTransferUsageFault;
|
||||
}
|
||||
|
||||
seq = transfer->seq;
|
||||
for (;; ) {
|
||||
pending = i2c->IF;
|
||||
|
||||
/* If some sort of fault, abort transfer. */
|
||||
if (pending & I2C_IF_ERRORS) {
|
||||
if (pending & I2C_IF_ARBLOST) {
|
||||
/* If arbitration fault, it indicates either a slave device */
|
||||
/* not responding as expected, or other master which is not */
|
||||
/* supported by this SW. */
|
||||
transfer->result = i2cTransferArbLost;
|
||||
} else if (pending & I2C_IF_BUSERR) {
|
||||
/* A bus error indicates a misplaced start or stop, which should */
|
||||
/* not occur in master mode controlled by this SW. */
|
||||
transfer->result = i2cTransferBusErr;
|
||||
}
|
||||
|
||||
/* If error situation occurred, it is difficult to know */
|
||||
/* exact cause and how to resolve. It will be up to a wrapper */
|
||||
/* to determine how to handle a fault/recovery if possible. */
|
||||
transfer->state = i2cStateDone;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (transfer->state) {
|
||||
/***************************************************/
|
||||
/* Send first start+address (first byte if 10 bit) */
|
||||
/***************************************************/
|
||||
case i2cStateStartAddrSend:
|
||||
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
|
||||
tmp = (((uint32_t)(seq->addr) >> 8) & 0x06) | 0xf0;
|
||||
|
||||
/* In 10 bit address mode, the address following the first */
|
||||
/* start always indicate write. */
|
||||
} else {
|
||||
tmp = (uint32_t)(seq->addr) & 0xfe;
|
||||
|
||||
if (seq->flags & I2C_FLAG_READ) {
|
||||
/* Indicate read request */
|
||||
tmp |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
transfer->state = i2cStateAddrWFAckNack;
|
||||
i2c->TXDATA = tmp;/* Data not transmitted until START sent */
|
||||
i2c->CMD = I2C_CMD_START;
|
||||
goto done;
|
||||
|
||||
/*******************************************************/
|
||||
/* Wait for ACK/NACK on address (first byte if 10 bit) */
|
||||
/*******************************************************/
|
||||
case i2cStateAddrWFAckNack:
|
||||
if (pending & I2C_IF_NACK) {
|
||||
i2c->IFC = I2C_IFC_NACK;
|
||||
transfer->result = i2cTransferNack;
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
} else if (pending & I2C_IF_ACK) {
|
||||
i2c->IFC = I2C_IFC_ACK;
|
||||
|
||||
/* If 10 bit address, send 2nd byte of address. */
|
||||
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
|
||||
transfer->state = i2cStateAddrWF2ndAckNack;
|
||||
i2c->TXDATA = (uint32_t)(seq->addr) & 0xff;
|
||||
} else {
|
||||
/* Determine whether receiving or sending data */
|
||||
if (seq->flags & I2C_FLAG_READ) {
|
||||
transfer->state = i2cStateWFData;
|
||||
if (seq->buf[transfer->bufIndx].len == 1) {
|
||||
i2c->CMD = I2C_CMD_NACK;
|
||||
}
|
||||
} else {
|
||||
transfer->state = i2cStateDataSend;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
|
||||
/******************************************************/
|
||||
/* Wait for ACK/NACK on second byte of 10 bit address */
|
||||
/******************************************************/
|
||||
case i2cStateAddrWF2ndAckNack:
|
||||
if (pending & I2C_IF_NACK) {
|
||||
i2c->IFC = I2C_IFC_NACK;
|
||||
transfer->result = i2cTransferNack;
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
} else if (pending & I2C_IF_ACK) {
|
||||
i2c->IFC = I2C_IFC_ACK;
|
||||
|
||||
/* If using plain read sequence with 10 bit address, switch to send */
|
||||
/* repeated start. */
|
||||
if (seq->flags & I2C_FLAG_READ) {
|
||||
transfer->state = i2cStateRStartAddrSend;
|
||||
}
|
||||
/* Otherwise expected to write 0 or more bytes */
|
||||
else {
|
||||
transfer->state = i2cStateDataSend;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
goto done;
|
||||
|
||||
/*******************************/
|
||||
/* Send repeated start+address */
|
||||
/*******************************/
|
||||
case i2cStateRStartAddrSend:
|
||||
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
|
||||
tmp = ((seq->addr >> 8) & 0x06) | 0xf0;
|
||||
} else {
|
||||
tmp = seq->addr & 0xfe;
|
||||
}
|
||||
|
||||
/* If this is a write+read combined sequence, then read is about to start */
|
||||
if (seq->flags & I2C_FLAG_WRITE_READ) {
|
||||
/* Indicate read request */
|
||||
tmp |= 1;
|
||||
}
|
||||
|
||||
transfer->state = i2cStateRAddrWFAckNack;
|
||||
/* We have to write START cmd first since repeated start, otherwise */
|
||||
/* data would be sent first. */
|
||||
i2c->CMD = I2C_CMD_START;
|
||||
i2c->TXDATA = tmp;
|
||||
goto done;
|
||||
|
||||
/**********************************************************************/
|
||||
/* Wait for ACK/NACK on repeated start+address (first byte if 10 bit) */
|
||||
/**********************************************************************/
|
||||
case i2cStateRAddrWFAckNack:
|
||||
if (pending & I2C_IF_NACK) {
|
||||
i2c->IFC = I2C_IFC_NACK;
|
||||
transfer->result = i2cTransferNack;
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
} else if (pending & I2C_IF_ACK) {
|
||||
i2c->IFC = I2C_IFC_ACK;
|
||||
|
||||
/* Determine whether receiving or sending data */
|
||||
if (seq->flags & I2C_FLAG_WRITE_READ) {
|
||||
transfer->state = i2cStateWFData;
|
||||
} else {
|
||||
transfer->state = i2cStateDataSend;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
|
||||
/*****************************/
|
||||
/* Send a data byte to slave */
|
||||
/*****************************/
|
||||
case i2cStateDataSend:
|
||||
/* Reached end of data buffer? */
|
||||
if (transfer->offset >= seq->buf[transfer->bufIndx].len) {
|
||||
/* Move to next message part */
|
||||
transfer->offset = 0;
|
||||
transfer->bufIndx++;
|
||||
|
||||
/* Send repeated start when switching to read mode on 2nd buffer */
|
||||
if (seq->flags & I2C_FLAG_WRITE_READ) {
|
||||
transfer->state = i2cStateRStartAddrSend;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only writing from one buffer, or finished both buffers */
|
||||
if ((seq->flags & I2C_FLAG_WRITE) || (transfer->bufIndx > 1)) {
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Reprocess in case next buffer is empty */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Send byte */
|
||||
i2c->TXDATA = (uint32_t)(seq->buf[transfer->bufIndx].data[transfer->offset++]);
|
||||
transfer->state = i2cStateDataWFAckNack;
|
||||
goto done;
|
||||
|
||||
/*********************************************************/
|
||||
/* Wait for ACK/NACK from slave after sending data to it */
|
||||
/*********************************************************/
|
||||
case i2cStateDataWFAckNack:
|
||||
if (pending & I2C_IF_NACK) {
|
||||
i2c->IFC = I2C_IFC_NACK;
|
||||
transfer->result = i2cTransferNack;
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
} else if (pending & I2C_IF_ACK) {
|
||||
i2c->IFC = I2C_IFC_ACK;
|
||||
transfer->state = i2cStateDataSend;
|
||||
continue;
|
||||
}
|
||||
goto done;
|
||||
|
||||
/****************************/
|
||||
/* Wait for data from slave */
|
||||
/****************************/
|
||||
case i2cStateWFData:
|
||||
if (pending & I2C_IF_RXDATAV) {
|
||||
uint8_t data;
|
||||
unsigned int rxLen = seq->buf[transfer->bufIndx].len;
|
||||
|
||||
/* Must read out data in order to not block further progress */
|
||||
data = (uint8_t)(i2c->RXDATA);
|
||||
|
||||
/* Make sure not storing beyond end of buffer just in case */
|
||||
if (transfer->offset < rxLen) {
|
||||
seq->buf[transfer->bufIndx].data[transfer->offset++] = data;
|
||||
}
|
||||
|
||||
/* If we have read all requested data, then the sequence should end */
|
||||
if (transfer->offset >= rxLen) {
|
||||
/* If there is only one byte to receive we need to transmit the
|
||||
NACK now, before the stop. */
|
||||
if (1 == rxLen) {
|
||||
i2c->CMD = I2C_CMD_NACK;
|
||||
}
|
||||
|
||||
transfer->state = i2cStateWFStopSent;
|
||||
i2c->CMD = I2C_CMD_STOP;
|
||||
} else {
|
||||
/* Send ACK and wait for next byte */
|
||||
i2c->CMD = I2C_CMD_ACK;
|
||||
|
||||
if ( (1 < rxLen) && (transfer->offset == (rxLen - 1)) ) {
|
||||
/* If there is more than one byte to receive and this is the next
|
||||
to last byte we need to transmit the NACK now, before receiving
|
||||
the last byte. */
|
||||
i2c->CMD = I2C_CMD_NACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
|
||||
/***********************************/
|
||||
/* Wait for STOP to have been sent */
|
||||
/***********************************/
|
||||
case i2cStateWFStopSent:
|
||||
if (pending & I2C_IF_MSTOP) {
|
||||
i2c->IFC = I2C_IFC_MSTOP;
|
||||
transfer->state = i2cStateDone;
|
||||
}
|
||||
goto done;
|
||||
|
||||
/******************************/
|
||||
/* Unexpected state, SW fault */
|
||||
/******************************/
|
||||
default:
|
||||
transfer->result = i2cTransferSwFault;
|
||||
transfer->state = i2cStateDone;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (transfer->state == i2cStateDone) {
|
||||
/* Disable interrupt sources when done */
|
||||
i2c->IEN = 0;
|
||||
|
||||
/* Update result unless some fault already occurred */
|
||||
if (transfer->result == i2cTransferInProgress) {
|
||||
transfer->result = i2cTransferDone;
|
||||
}
|
||||
}
|
||||
/* Until transfer is done keep returning i2cTransferInProgress */
|
||||
else {
|
||||
return i2cTransferInProgress;
|
||||
}
|
||||
|
||||
return transfer->result;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Prepare and start an I2C transfer (single master mode only).
|
||||
*
|
||||
* @details
|
||||
* This function must be invoked in order to start an I2C transfer
|
||||
* sequence. In order to actually complete the transfer, I2C_Transfer() must
|
||||
* be used either in polled mode or by adding a small driver wrapper utilizing
|
||||
* interrupts.
|
||||
*
|
||||
* @note
|
||||
* Only single master mode is supported.
|
||||
*
|
||||
* @param[in] i2c
|
||||
* Pointer to I2C peripheral register block.
|
||||
*
|
||||
* @param[in] seq
|
||||
* Pointer to sequence structure defining the I2C transfer to take place. The
|
||||
* referenced structure must exist until the transfer has fully completed.
|
||||
*
|
||||
* @return
|
||||
* Returns status for ongoing transfer:
|
||||
* @li #i2cTransferInProgress - indicates that transfer not finished.
|
||||
* @li otherwise some sort of error has occurred.
|
||||
******************************************************************************/
|
||||
I2C_TransferReturn_TypeDef I2C_TransferInit(I2C_TypeDef *i2c,
|
||||
I2C_TransferSeq_TypeDef *seq)
|
||||
{
|
||||
I2C_Transfer_TypeDef *transfer;
|
||||
|
||||
EFM_ASSERT(I2C_REF_VALID(i2c));
|
||||
EFM_ASSERT(seq);
|
||||
|
||||
/* Support up to 2 I2C buses */
|
||||
if (i2c == I2C0) {
|
||||
transfer = i2cTransfer;
|
||||
}
|
||||
#if (I2C_COUNT > 1)
|
||||
else if (i2c == I2C1) {
|
||||
transfer = i2cTransfer + 1;
|
||||
}
|
||||
#endif
|
||||
#if (I2C_COUNT > 2)
|
||||
else if (i2c == I2C2) {
|
||||
transfer = i2cTransfer + 2;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return i2cTransferUsageFault;
|
||||
}
|
||||
|
||||
/* Check if in busy state. Since this SW assumes single master, we can */
|
||||
/* just issue an abort. The BUSY state is normal after a reset. */
|
||||
if (i2c->STATE & I2C_STATE_BUSY) {
|
||||
i2c->CMD = I2C_CMD_ABORT;
|
||||
}
|
||||
|
||||
/* Make sure user is not trying to read 0 bytes, it is not */
|
||||
/* possible according to I2C spec, since slave will always start */
|
||||
/* sending first byte ACK on address. The read operation can */
|
||||
/* only be stopped by NACKing a received byte, ie minimum 1 byte. */
|
||||
if (((seq->flags & I2C_FLAG_READ) && !(seq->buf[0].len))
|
||||
|| ((seq->flags & I2C_FLAG_WRITE_READ) && !(seq->buf[1].len))
|
||||
) {
|
||||
return i2cTransferUsageFault;
|
||||
}
|
||||
|
||||
/* Prepare for a transfer */
|
||||
transfer->state = i2cStateStartAddrSend;
|
||||
transfer->result = i2cTransferInProgress;
|
||||
transfer->offset = 0;
|
||||
transfer->bufIndx = 0;
|
||||
transfer->seq = seq;
|
||||
|
||||
/* Ensure buffers are empty */
|
||||
i2c->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
|
||||
if (i2c->IF & I2C_IF_RXDATAV) {
|
||||
(void)i2c->RXDATA;
|
||||
}
|
||||
|
||||
/* Clear all pending interrupts prior to starting transfer. */
|
||||
i2c->IFC = _I2C_IFC_MASK;
|
||||
|
||||
/* Enable those interrupts we are interested in throughout transfer. */
|
||||
/* Notice that the I2C interrupt must also be enabled in the NVIC, but */
|
||||
/* that is left for an additional driver wrapper. */
|
||||
i2c->IEN |= I2C_IF_NACK | I2C_IF_ACK | I2C_IF_MSTOP
|
||||
| I2C_IF_RXDATAV | I2C_IF_ERRORS;
|
||||
|
||||
/* Start transfer */
|
||||
return I2C_Transfer(i2c);
|
||||
}
|
||||
|
||||
/** @} (end addtogroup I2C) */
|
||||
/** @} (end addtogroup emlib) */
|
||||
#endif /* defined(I2C_COUNT) && (I2C_COUNT > 0) */
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* nfc.h
|
||||
*
|
||||
* Created on: Jul 22, 2018
|
||||
* Author: conor
|
||||
*/
|
||||
|
||||
#ifndef INC_NFC_H_
|
||||
#define INC_NFC_H_
|
||||
|
||||
void nfc_test();
|
||||
|
||||
#endif /* INC_NFC_H_ */
|
|
@ -23,7 +23,7 @@
|
|||
#include "em_cryotimer.h"
|
||||
#include "em_crypto.h"
|
||||
#include "em_gpio.h"
|
||||
#include "em_ldma.h"
|
||||
#include "em_i2c.h"
|
||||
#include "em_usart.h"
|
||||
// [Library includes]$
|
||||
|
||||
|
@ -39,7 +39,7 @@ extern void enter_DefaultMode_from_RESET(void) {
|
|||
ADC0_enter_DefaultMode_from_RESET();
|
||||
USART0_enter_DefaultMode_from_RESET();
|
||||
USART1_enter_DefaultMode_from_RESET();
|
||||
LDMA_enter_DefaultMode_from_RESET();
|
||||
I2C0_enter_DefaultMode_from_RESET();
|
||||
CRYOTIMER_enter_DefaultMode_from_RESET();
|
||||
PORTIO_enter_DefaultMode_from_RESET();
|
||||
// [Config Calls]$
|
||||
|
@ -104,7 +104,7 @@ extern void CMU_enter_DefaultMode_from_RESET(void) {
|
|||
CMU_HFXOInit(&hfxoInit);
|
||||
|
||||
/* Setting system HFRCO frequency */
|
||||
CMU_HFRCOFreqSet (cmuHFRCOFreq_38M0Hz);
|
||||
CMU_HFRCOFreqSet (cmuHFRCOFreq_13M0Hz);
|
||||
|
||||
/* Using HFRCO as high frequency clock, HFCLK */
|
||||
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
|
||||
|
@ -135,8 +135,8 @@ extern void CMU_enter_DefaultMode_from_RESET(void) {
|
|||
/* Enable clock for CRYOTIMER */
|
||||
CMU_ClockEnable(cmuClock_CRYOTIMER, true);
|
||||
|
||||
/* Enable clock for LDMA */
|
||||
CMU_ClockEnable(cmuClock_LDMA, true);
|
||||
/* Enable clock for I2C0 */
|
||||
CMU_ClockEnable(cmuClock_I2C0, true);
|
||||
|
||||
/* Enable clock for USART0 */
|
||||
CMU_ClockEnable(cmuClock_USART0, true);
|
||||
|
@ -455,9 +455,24 @@ extern void WDOG0_enter_DefaultMode_from_RESET(void) {
|
|||
extern void I2C0_enter_DefaultMode_from_RESET(void) {
|
||||
|
||||
// $[I2C0 I/O setup]
|
||||
/* Set up SCL */
|
||||
I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SCLPEN;
|
||||
I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK))
|
||||
| I2C_ROUTELOC0_SCLLOC_LOC3;
|
||||
/* Set up SDA */
|
||||
I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SDAPEN;
|
||||
I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK))
|
||||
| I2C_ROUTELOC0_SDALOC_LOC27;
|
||||
// [I2C0 I/O setup]$
|
||||
|
||||
// $[I2C0 initialization]
|
||||
I2C_Init_TypeDef init = I2C_INIT_DEFAULT;
|
||||
|
||||
init.enable = 1;
|
||||
init.master = 1;
|
||||
init.freq = I2C_FREQ_STANDARD_MAX;
|
||||
init.clhr = i2cClockHLRStandard;
|
||||
I2C_Init(I2C0, &init);
|
||||
// [I2C0 initialization]$
|
||||
|
||||
}
|
||||
|
@ -610,6 +625,9 @@ extern void PORTIO_enter_DefaultMode_from_RESET(void) {
|
|||
/* Pin PA3 is configured to Push-pull */
|
||||
GPIO_PinModeSet(gpioPortA, 3, gpioModePushPull, 0);
|
||||
|
||||
/* Pin PA4 is configured to Open-drain with pull-up and filter */
|
||||
GPIO_PinModeSet(gpioPortA, 4, gpioModeWiredAndPullUpFilter, 0);
|
||||
|
||||
/* Pin PA5 is configured to Push-pull */
|
||||
GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 1);
|
||||
// [Port A Configuration]$
|
||||
|
@ -649,6 +667,9 @@ extern void PORTIO_enter_DefaultMode_from_RESET(void) {
|
|||
|
||||
// $[Port F Configuration]
|
||||
|
||||
/* Pin PF3 is configured to Open-drain with pull-up and filter */
|
||||
GPIO_PinModeSet(gpioPortF, 3, gpioModeWiredAndPullUpFilter, 0);
|
||||
|
||||
/* Pin PF4 is configured to Push-pull */
|
||||
GPIO_PinModeSet(gpioPortF, 4, gpioModePushPull, 0);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "em_adc.h"
|
||||
#include "em_cmu.h"
|
||||
#include "em_msc.h"
|
||||
#include "em_i2c.h"
|
||||
|
||||
#include "InitDevice.h"
|
||||
#include "cbor.h"
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "app.h"
|
||||
#include "uECC.h"
|
||||
#include "crypto.h"
|
||||
#include "nfc.h"
|
||||
|
||||
#define MSG_AVAIL_PIN gpioPortC,9
|
||||
#define RDY_PIN gpioPortC,10
|
||||
|
@ -117,17 +119,19 @@ int ctap_user_presence_test()
|
|||
|
||||
// Must be implemented by application
|
||||
// data is HID_MESSAGE_SIZE long in bytes
|
||||
#ifndef TEST_POWER
|
||||
void ctaphid_write_block(uint8_t * data)
|
||||
{
|
||||
printf1(TAG_DUMP,"<< "); dump_hex1(TAG_DUMP, data, HID_MESSAGE_SIZE);
|
||||
usbhid_send(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
void heartbeat()
|
||||
{
|
||||
GPIO_PinOutToggle(gpioPortF,4);
|
||||
GPIO_PinOutToggle(gpioPortF,5);
|
||||
|
||||
nfc_test();
|
||||
// printf("heartbeat %d %d\r\n", beat++,CRYOTIMER->CNT);
|
||||
}
|
||||
|
||||
|
@ -158,6 +162,7 @@ static void wait_for_efm8_busy()
|
|||
;
|
||||
}
|
||||
|
||||
#ifndef TEST_POWER
|
||||
int usbhid_recv(uint8_t * msg)
|
||||
{
|
||||
int i;
|
||||
|
@ -188,6 +193,8 @@ int usbhid_recv(uint8_t * msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usbhid_send(uint8_t * msg)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* nfc.c
|
||||
*
|
||||
* Created on: Jul 22, 2018
|
||||
* Author: conor
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "em_chip.h"
|
||||
#include "em_gpio.h"
|
||||
#include "em_i2c.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "nfc.h"
|
||||
#include "app.h"
|
||||
|
||||
|
||||
I2C_TransferReturn_TypeDef I2CSPM_Transfer(I2C_TypeDef *i2c, I2C_TransferSeq_TypeDef *seq)
|
||||
{
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
uint32_t timeout = 10000;
|
||||
/* Do a polled transfer */
|
||||
ret = I2C_TransferInit(i2c, seq);
|
||||
while (ret == i2cTransferInProgress && timeout--)
|
||||
{
|
||||
ret = I2C_Transfer(i2c);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// data must be 16 bytes
|
||||
void read_block(uint8_t block, uint8_t * data)
|
||||
{
|
||||
uint8_t addr = 0xAA;
|
||||
I2C_TransferSeq_TypeDef seq;
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
uint8_t i2c_read_data[16];
|
||||
uint8_t i2c_write_data[1];
|
||||
|
||||
seq.addr = addr;
|
||||
seq.flags = I2C_FLAG_WRITE_READ;
|
||||
/* Select command to issue */
|
||||
i2c_write_data[0] = block;
|
||||
seq.buf[0].data = i2c_write_data;
|
||||
seq.buf[0].len = 1;
|
||||
/* Select location/length of data to be read */
|
||||
seq.buf[1].data = i2c_read_data;
|
||||
seq.buf[1].len = 16;
|
||||
|
||||
ret = I2CSPM_Transfer(I2C0, &seq);
|
||||
|
||||
if (ret != i2cTransferDone) {
|
||||
printf("I2C fail %04x\r\n",ret);
|
||||
exit(1);
|
||||
}
|
||||
memmove(data, i2c_read_data, 16);
|
||||
}
|
||||
void write_reg_flash(uint8_t reg_addr, uint8_t mask,uint8_t data)
|
||||
{
|
||||
uint8_t addr = 0xAA;
|
||||
I2C_TransferSeq_TypeDef seq;
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
uint8_t i2c_write_data[4];
|
||||
|
||||
seq.addr = addr;
|
||||
seq.flags = I2C_FLAG_WRITE;
|
||||
i2c_write_data[0] = 0x3a;
|
||||
i2c_write_data[1] = reg_addr;
|
||||
i2c_write_data[2] = mask;
|
||||
i2c_write_data[3] = data;
|
||||
|
||||
seq.buf[0].data = i2c_write_data;
|
||||
seq.buf[0].len = 4;
|
||||
seq.buf[1].data = NULL;
|
||||
seq.buf[1].len = 0;
|
||||
|
||||
ret = I2CSPM_Transfer(I2C0, &seq);
|
||||
|
||||
if (ret != i2cTransferDone) {
|
||||
printf("I2C fail %04x\r\n",ret);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
void write_reg(uint8_t reg_addr, uint8_t mask,uint8_t data)
|
||||
{
|
||||
uint8_t addr = 0xAA;
|
||||
I2C_TransferSeq_TypeDef seq;
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
uint8_t i2c_write_data[4];
|
||||
|
||||
seq.addr = addr;
|
||||
seq.flags = I2C_FLAG_WRITE;
|
||||
i2c_write_data[0] = 0xFE;
|
||||
i2c_write_data[1] = reg_addr;
|
||||
i2c_write_data[2] = mask;
|
||||
i2c_write_data[3] = data;
|
||||
|
||||
seq.buf[0].data = i2c_write_data;
|
||||
seq.buf[0].len = 4;
|
||||
seq.buf[1].data = NULL;
|
||||
seq.buf[1].len = 0;
|
||||
|
||||
ret = I2CSPM_Transfer(I2C0, &seq);
|
||||
|
||||
if (ret != i2cTransferDone) {
|
||||
printf("I2C fail %04x\r\n",ret);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t read_reg(uint8_t reg_addr)
|
||||
{
|
||||
I2C_TransferSeq_TypeDef seq;
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
uint8_t write_data[2];
|
||||
uint8_t read_data[1];
|
||||
|
||||
seq.addr = 0xAA;
|
||||
seq.flags = I2C_FLAG_WRITE_READ;
|
||||
write_data[0] = 0xFE;
|
||||
write_data[1] = reg_addr;
|
||||
|
||||
seq.buf[0].data = write_data;
|
||||
seq.buf[0].len = 2;
|
||||
seq.buf[1].data = read_data;
|
||||
seq.buf[1].len = 1;
|
||||
|
||||
ret = I2CSPM_Transfer(I2C0, &seq);
|
||||
|
||||
if (ret != i2cTransferDone) {
|
||||
printf("I2C fail %04x\r\n",ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return read_data[0];
|
||||
}
|
||||
|
||||
void read_reg_block(uint8_t * data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
*data = read_reg(i);
|
||||
// printf("data %d: %x\n" ,i,(int)(*data));
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nfc_test()
|
||||
{
|
||||
uint8_t data[16];
|
||||
printf("-NFC test-\n");
|
||||
|
||||
read_block(0x00, data);
|
||||
printf("block 00: "); dump_hex(data,16);
|
||||
|
||||
read_reg_block(data);
|
||||
printf("block 3A [init]:"); dump_hex(data,8);
|
||||
|
||||
write_reg(0, 0xff, 0x43);
|
||||
write_reg_flash(0, 0xff, 0x43);
|
||||
write_reg(2, 0xff, 0x01);
|
||||
|
||||
read_reg_block(data);
|
||||
printf("block 3A [done]:"); dump_hex(data,8);
|
||||
//
|
||||
// read_block(0x3A, data);
|
||||
// printf("block 3A [done]:"); dump_hex(data,16);
|
||||
|
||||
while(1)
|
||||
;
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#if !defined(TEST)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "app.h"
|
||||
#ifdef TEST_POWER
|
||||
|
||||
/*
|
||||
|
@ -13,15 +14,29 @@
|
|||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
|
||||
//#define BUTT NRF_GPIO_PIN_MAP(0,11)
|
||||
//#define TRIG NRF_GPIO_PIN_MAP(0,30)
|
||||
//
|
||||
//#define GPIO_CLEAR(PIN) nrf_gpio_pin_clear(PIN)
|
||||
//#define GPIO_SET(PIN) nrf_gpio_pin_set(PIN)
|
||||
//#define GPIO_OUTPUT(PIN) nrf_gpio_cfg_output(PIN)
|
||||
//#define GPIO_INPUT(PIN) nrf_gpio_cfg_input(PIN,NRF_GPIO_PIN_PULLUP)
|
||||
//#define GPIO_READ(PIN) nrf_gpio_pin_read(PIN)
|
||||
|
||||
#include "em_gpio.h"
|
||||
#define BUTT gpioPortF,6
|
||||
#define TRIG gpioPortD,14
|
||||
|
||||
#define GPIO_CLEAR(PIN) GPIO_PinOutClear(PIN)
|
||||
#define GPIO_SET(PIN) GPIO_PinOutSet(PIN)
|
||||
#define GPIO_OUTPUT(PIN) GPIO_PinModeSet(PIN,gpioModePushPull,1)
|
||||
#define GPIO_INPUT(PIN) GPIO_PinModeSet(PIN,gpioModeInputPull,1)
|
||||
#define GPIO_READ(PIN) GPIO_PinInGet(PIN)
|
||||
|
||||
#define BUTT NRF_GPIO_PIN_MAP(0,11)
|
||||
#define TRIG NRF_GPIO_PIN_MAP(0,30)
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
|
@ -45,16 +60,16 @@ int main(int argc, char * argv[])
|
|||
/*TAG_DUMP|*/
|
||||
/*TAG_GREEN|*/
|
||||
/*TAG_RED|*/
|
||||
/*TAG_ERR*/
|
||||
|TAG_ERR
|
||||
);
|
||||
|
||||
device_init();
|
||||
ctaphid_init();
|
||||
ctap_init();
|
||||
|
||||
nrf_gpio_cfg_input(BUTT, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_output(TRIG);
|
||||
nrf_gpio_pin_clear(TRIG);
|
||||
GPIO_INPUT(BUTT);
|
||||
GPIO_OUTPUT(TRIG);
|
||||
GPIO_CLEAR(TRIG);
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
|
@ -92,13 +107,7 @@ int main(int argc, char * argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
void delay(int ms)
|
||||
{
|
||||
uint64_t t1;
|
||||
t1 = millis();
|
||||
while(millis()-t1 < ms)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void ctaphid_write_block(uint8_t * data)
|
||||
{
|
||||
|
@ -130,8 +139,8 @@ int usbhid_recv(uint8_t * msg)
|
|||
if (!reading)
|
||||
{
|
||||
delay(1);
|
||||
nrf_gpio_pin_clear(TRIG);
|
||||
val = nrf_gpio_pin_read(BUTT);
|
||||
GPIO_CLEAR(TRIG);
|
||||
val = GPIO_READ(BUTT);
|
||||
if (val == 0)
|
||||
{
|
||||
if (lastval != 0)
|
||||
|
@ -145,7 +154,7 @@ int usbhid_recv(uint8_t * msg)
|
|||
}
|
||||
else
|
||||
{
|
||||
nrf_gpio_pin_set(TRIG);
|
||||
GPIO_SET(TRIG);
|
||||
memmove(msg, hidcmds[reading-1], 64);
|
||||
reading++;
|
||||
if (reading-1 == sizeof(hidcmds)/64)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
import datetime,sys
|
||||
from binascii import hexlify
|
||||
|
||||
import Chameleon
|
||||
|
||||
def verboseLog(text):
|
||||
formatString = "[{}] {}"
|
||||
timeString = datetime.datetime.utcnow()
|
||||
print(formatString.format(timeString, text), )
|
||||
|
||||
chameleon = Chameleon.Device(verboseLog)
|
||||
|
||||
p = None
|
||||
for p in Chameleon.Device.listDevices():
|
||||
break
|
||||
|
||||
if p:
|
||||
chameleon.connect(p)
|
||||
else:
|
||||
raise RuntimeError('No chameleon mini connected')
|
||||
|
||||
chameleon.execCmd('LOGMODE=LIVE')
|
||||
|
||||
while 1:
|
||||
b = chameleon.read(1,20)
|
||||
h = hexlify(b)
|
||||
h = h.decode()
|
||||
sys.stdout.write(h)
|
||||
sys.stdout.flush()
|
||||
|
||||
chameleon.execCmd('LOGMODE=NONE')
|
Ładowanie…
Reference in New Issue