diff --git a/.gitignore b/.gitignore index 2571b5f..e80f85c 100644 --- a/.gitignore +++ b/.gitignore @@ -81,15 +81,5 @@ env3/ .tags* targets/*/docs/ main -targets/efm32/.project -targets/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs -targets/efm32/.settings/org.eclipse.cdt.codan.core.prefs -targets/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s -targets/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c -targets/efm32/EFM32.hwconf -targets/efm32/EFM32_EFM32JG1B200F128GM32.hwconf -targets/efm32/emlib/em_adc.c -targets/efm32/emlib/em_assert.c -targets/efm32/emlib/em_cmu.c builds/* diff --git a/fido2/apdu.h b/fido2/apdu.h new file mode 100644 index 0000000..d9687c7 --- /dev/null +++ b/fido2/apdu.h @@ -0,0 +1,30 @@ +#ifndef _APDU_H_ +#define _APDU_H_ + +#include + +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc; +} __attribute__((packed)) APDU_HEADER; + +#define APDU_FIDO_U2F_REGISTER 0x01 +#define APDU_FIDO_U2F_AUTHENTICATE 0x02 +#define APDU_FIDO_U2F_VERSION 0x03 +#define APDU_FIDO_NFCCTAP_MSG 0x10 +#define APDU_INS_SELECT 0xA4 +#define APDU_INS_READ_BINARY 0xB0 + +#define SW_SUCCESS 0x9000 +#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE. +#define SW_WRONG_LENGTH 0x6700 +#define SW_COND_USE_NOT_SATISFIED 0x6985 +#define SW_FILE_NOT_FOUND 0x6a82 +#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid +#define SW_INTERNAL_EXCEPTION 0x6f00 + +#endif //_APDU_H_ diff --git a/fido2/ctap.c b/fido2/ctap.c index 845e66f..ecdff80 100644 --- a/fido2/ctap.c +++ b/fido2/ctap.c @@ -336,7 +336,12 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au count = auth_data_update_count(&authData->head); device_set_status(CTAPHID_STATUS_UPNEEDED); - int but = ctap_user_presence_test(); + // if NFC - not need to click a button + int but = 1; + if(!device_is_nfc()) + { + but = ctap_user_presence_test(); + } if (!but) { @@ -1586,7 +1591,10 @@ void ctap_init() exit(1); } - crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV); + if (! device_is_nfc()) + { + crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV); + } #ifdef BRIDGE_TO_WALLET wallet_init(); diff --git a/fido2/device.h b/fido2/device.h index e75f250..109d25a 100644 --- a/fido2/device.h +++ b/fido2/device.h @@ -86,5 +86,22 @@ void boot_st_bootloader(); // HID wink command void device_wink(); +typedef enum { + DEVICE_LOW_POWER_IDLE = 0, + DEVICE_LOW_POWER_FAST = 1, + DEVICE_FAST = 2, +} DEVICE_CLOCK_RATE; + +// Set the clock rate for the device. +// Three modes are targetted for Solo. +// 0: Lowest clock rate for NFC. +// 1: fastest clock rate supported at a low power setting for NFC FIDO. +// 2: fastest clock rate. Generally for USB interface. +void device_set_clock_rate(DEVICE_CLOCK_RATE param); + +// Returns 1 if operating in NFC mode. +// 0 otherwise. +bool device_is_nfc(); + #endif diff --git a/fido2/extensions/extensions.c b/fido2/extensions/extensions.c index 9dcaca2..ae669ea 100644 --- a/fido2/extensions/extensions.c +++ b/fido2/extensions/extensions.c @@ -91,10 +91,10 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output) } } -int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len) +int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len) { - struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) req->payload; + struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) payload; uint16_t rcode; if (req->ins == U2F_AUTHENTICATE) diff --git a/fido2/extensions/extensions.h b/fido2/extensions/extensions.h index ea871a5..2d602c1 100644 --- a/fido2/extensions/extensions.h +++ b/fido2/extensions/extensions.h @@ -7,8 +7,9 @@ #ifndef EXTENSIONS_H_ #define EXTENSIONS_H_ #include "u2f.h" +#include "apdu.h" -int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len); +int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len); int16_t extend_fido2(CredentialId * credid, uint8_t * output); diff --git a/fido2/log.c b/fido2/log.c index 04764d6..c4d874e 100644 --- a/fido2/log.c +++ b/fido2/log.c @@ -48,6 +48,8 @@ struct logtag tagtable[] = { {TAG_STOR,"STOR"}, {TAG_BOOT,"BOOT"}, {TAG_EXT,"EXT"}, + {TAG_NFC,"NFC"}, + {TAG_NFC_APDU, "NAPDU"}, }; @@ -68,7 +70,7 @@ void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...) { if (tag & tagtable[i].tagn) { - if (tagtable[i].tag[0]) printf("[%s] ", tagtable[i].tag); + if (tagtable[i].tag[0] && !(tag & TAG_NO_TAG)) printf("[%s] ", tagtable[i].tag); i = 0; break; } diff --git a/fido2/log.h b/fido2/log.h index e5ded84..d7190cf 100644 --- a/fido2/log.h +++ b/fido2/log.h @@ -23,27 +23,30 @@ void set_logging_tag(uint32_t tag); typedef enum { - TAG_GEN = (1 << 0), - TAG_MC = (1 << 1), - TAG_GA = (1 << 2), - TAG_CP = (1 << 3), - TAG_ERR = (1 << 4), - TAG_PARSE= (1 << 5), - TAG_CTAP = (1 << 6), - TAG_U2F = (1 << 7), - TAG_DUMP = (1 << 8), - TAG_GREEN = (1 << 9), - TAG_RED= (1 << 10), - TAG_TIME= (1 << 11), - TAG_HID = (1 << 12), - TAG_USB = (1 << 13), - TAG_WALLET = (1 << 14), - TAG_STOR = (1 << 15), - TAG_DUMP2 = (1 << 16), - TAG_BOOT = (1 << 17), - TAG_EXT = (1 << 18), + TAG_GEN = (1 << 0), + TAG_MC = (1 << 1), + TAG_GA = (1 << 2), + TAG_CP = (1 << 3), + TAG_ERR = (1 << 4), + TAG_PARSE = (1 << 5), + TAG_CTAP = (1 << 6), + TAG_U2F = (1 << 7), + TAG_DUMP = (1 << 8), + TAG_GREEN = (1 << 9), + TAG_RED = (1 << 10), + TAG_TIME = (1 << 11), + TAG_HID = (1 << 12), + TAG_USB = (1 << 13), + TAG_WALLET = (1 << 14), + TAG_STOR = (1 << 15), + TAG_DUMP2 = (1 << 16), + TAG_BOOT = (1 << 17), + TAG_EXT = (1 << 18), + TAG_NFC = (1 << 19), + TAG_NFC_APDU = (1 << 20), - TAG_FILENO = (1u << 31) + TAG_NO_TAG = (1UL << 30), + TAG_FILENO = (1UL << 31) } LOG_TAG; #if DEBUG_LEVEL > 0 diff --git a/fido2/main.c b/fido2/main.c index dbe6301..0ed2d90 100644 --- a/fido2/main.c +++ b/fido2/main.c @@ -25,40 +25,33 @@ int main() uint32_t t1 = 0; set_logging_mask( - /*0*/ - // TAG_GEN| - // TAG_MC | - // TAG_GA | - TAG_WALLET | - TAG_STOR | - // TAG_CP | - // TAG_CTAP| - // TAG_HID| - /*TAG_U2F|*/ - // TAG_PARSE | - // TAG_TIME| - // TAG_DUMP| - TAG_GREEN| - TAG_RED| - TAG_ERR - ); + /*0*/ + //TAG_GEN| + //TAG_MC | + //TAG_GA | + //TAG_WALLET | + TAG_STOR | + //TAG_NFC_APDU | + TAG_NFC | + //TAG_CP | + //TAG_CTAP| + //TAG_HID| + //TAG_U2F| + //TAG_PARSE | + //TAG_TIME| + //TAG_DUMP| + TAG_GREEN| + TAG_RED| + TAG_ERR + ); device_init(); - printf1(TAG_GEN,"init device\n"); - - usbhid_init(); - printf1(TAG_GEN,"init usb\n"); - ctaphid_init(); - printf1(TAG_GEN,"init ctaphid\n"); - - ctap_init(); - printf1(TAG_GEN,"init ctap\n"); memset(hidmsg,0,sizeof(hidmsg)); - printf1(TAG_GEN,"recv'ing hid msg \n"); + // printf1(TAG_GEN,"recv'ing hid msg \n"); while(1) @@ -80,6 +73,7 @@ int main() { } ctaphid_check_timeouts(); + } // Should never get here diff --git a/fido2/u2f.c b/fido2/u2f.c index 0bcd9b7..bbd82b0 100644 --- a/fido2/u2f.c +++ b/fido2/u2f.c @@ -10,6 +10,7 @@ #include "crypto.h" #include "log.h" #include "device.h" +#include "apdu.h" #include "wallet.h" #ifdef ENABLE_U2F_EXTENSIONS #include "extensions.h" @@ -27,12 +28,12 @@ void u2f_reset_response(); static CTAP_RESPONSE * _u2f_resp = NULL; -void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) +void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPONSE * resp) { uint16_t rcode = 0; - uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); uint8_t byte; + ctap_response_init(resp); u2f_set_writeback_buffer(resp); if (req->cla != 0) @@ -42,7 +43,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) goto end; } #ifdef ENABLE_U2F_EXTENSIONS - rcode = extend_u2f(req, len); + rcode = extend_u2f(req, payload, len); #endif if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything... { @@ -59,7 +60,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) { timestamp(); - rcode = u2f_register((struct u2f_register_request*)req->payload); + rcode = u2f_register((struct u2f_register_request*)payload); printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp()); } @@ -67,7 +68,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) case U2F_AUTHENTICATE: printf1(TAG_U2F, "U2F_AUTHENTICATE\n"); timestamp(); - rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1); + rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1); printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp()); break; case U2F_VERSION: @@ -109,6 +110,22 @@ end: printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length); } +void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp) +{ + if (len < 5 || !req) + return; + + uint32_t alen = req[4]; + + u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp); +} + +void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) +{ + uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); + + u2f_request_ex((APDU_HEADER *)req, req->payload, len, resp); +} int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len) { @@ -156,7 +173,7 @@ static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8 memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); } -static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey) +int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey) { ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE); u2f_make_auth_tag(kh, appid, kh->tag); @@ -203,12 +220,12 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c } else { - return U2F_SW_WRONG_DATA; + return U2F_SW_WRONG_PAYLOAD; } } if ( - control != U2F_AUTHENTICATE_SIGN || - req->khl != U2F_KEY_HANDLE_SIZE || + (control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) || + req->khl != U2F_KEY_HANDLE_SIZE || u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important u2f_load_key(&req->kh, req->app) != 0 @@ -217,12 +234,17 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c return U2F_SW_WRONG_DATA; } + // dont-enforce-user-presence-and-sign + if (control == U2F_AUTHENTICATE_SIGN_NO_USER) + up = 0; - - if (ctap_user_presence_test() == 0) - { - return U2F_SW_CONDITIONS_NOT_SATISFIED; - } + if(!device_is_nfc() && up) + { + if (ctap_user_presence_test() == 0) + { + return U2F_SW_CONDITIONS_NOT_SATISFIED; + } + } count = ctap_atomic_count(0); hash[0] = (count >> 24) & 0xff; @@ -231,14 +253,14 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c hash[3] = (count >> 0) & 0xff; crypto_sha256_init(); - crypto_sha256_update(req->app,32); - crypto_sha256_update(&up,1); - crypto_sha256_update(hash,4); - crypto_sha256_update(req->chal,32); + crypto_sha256_update(req->app, 32); + crypto_sha256_update(&up, 1); + crypto_sha256_update(hash, 4); + crypto_sha256_update(req->chal, 32); crypto_sha256_final(hash); - printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32); + printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F, hash, 32); crypto_ecc256_sign(hash, 32, sig); u2f_response_writeback(&up,1); @@ -264,10 +286,13 @@ static int16_t u2f_register(struct u2f_register_request * req) const uint16_t attest_size = attestation_cert_der_size; - if ( ! ctap_user_presence_test()) - { - return U2F_SW_CONDITIONS_NOT_SATISFIED; - } + if(!device_is_nfc()) + { + if ( ! ctap_user_presence_test()) + { + return U2F_SW_CONDITIONS_NOT_SATISFIED; + } + } if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1) { diff --git a/fido2/u2f.h b/fido2/u2f.h index 979ec2d..1fe7910 100644 --- a/fido2/u2f.h +++ b/fido2/u2f.h @@ -38,6 +38,7 @@ // U2F Authenticate #define U2F_AUTHENTICATE_CHECK 0x7 #define U2F_AUTHENTICATE_SIGN 0x3 +#define U2F_AUTHENTICATE_SIGN_NO_USER 0x8 // Command status responses @@ -94,9 +95,14 @@ struct u2f_authenticate_request }; // u2f_request send a U2F message to U2F protocol -// @req U2F message +// @req U2F message void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp); +// u2f_request send a U2F message to NFC protocol +// @req data with iso7816 apdu message +// @len data length +void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp); + int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); void u2f_reset_response(); diff --git a/pc/device.c b/pc/device.c index b4d5379..69a2509 100644 --- a/pc/device.c +++ b/pc/device.c @@ -461,3 +461,8 @@ void device_wink() { printf("*WINK*\n"); } + +bool device_is_nfc() +{ + return 0; +} diff --git a/targets/stm32l432/bootloader/bootloader.h b/targets/stm32l432/bootloader/bootloader.h index 013ed6a..8702f87 100644 --- a/targets/stm32l432/bootloader/bootloader.h +++ b/targets/stm32l432/bootloader/bootloader.h @@ -55,7 +55,7 @@ #define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION void printing_init(); -void hw_init(void); +void hw_init(int lf); // Trigger software reset void device_reboot(); diff --git a/targets/stm32l432/bootloader/main.c b/targets/stm32l432/bootloader/main.c index ad5cbf1..ef057ed 100644 --- a/targets/stm32l432/bootloader/main.c +++ b/targets/stm32l432/bootloader/main.c @@ -8,6 +8,10 @@ #include #include +#include "stm32l4xx_ll_rcc.h" +#include "stm32l4xx_ll_gpio.h" +#include "stm32l4xx.h" + #include "cbor.h" #include "device.h" #include "ctaphid.h" @@ -17,14 +21,13 @@ #include "ctap.h" #include "app.h" #include "memory_layout.h" -#include "stm32l4xx_ll_rcc.h" +#include "init.h" -#include "stm32l4xx.h" uint8_t REBOOT_FLAG = 0; -void BOOT_boot(void) +void BOOT_boot(void) { typedef void (*pFunction)(void); @@ -69,7 +72,16 @@ int main() TAG_ERR ); - device_init(); + // device_init(); + + init_gpio(); + + init_millisecond_timer(1); + +#if DEBUG_LEVEL > 0 + init_debug_uart(); +#endif + printf1(TAG_GEN,"init device\n"); t1 = millis(); @@ -107,7 +119,13 @@ int main() #ifdef SOLO_HACKER start_bootloader: #endif + SystemClock_Config(); + init_gpio(); + init_millisecond_timer(0); + init_pwm(); + init_rng(); usbhid_init(); + printf1(TAG_GEN,"init usb\n"); ctaphid_init(); diff --git a/targets/stm32l432/build/application.mk b/targets/stm32l432/build/application.mk index a22bc1d..576e029 100644 --- a/targets/stm32l432/build/application.mk +++ b/targets/stm32l432/build/application.mk @@ -2,7 +2,7 @@ include build/common.mk # ST related SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c -SRC += src/fifo.c src/crypto.c src/attestation.c +SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += $(DRIVER_LIBS) $(USB_LIB) @@ -41,7 +41,7 @@ DEBUG=0 endif DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES) -# DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1 +DEFINES += -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0 CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS) LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys diff --git a/targets/stm32l432/build/common.mk b/targets/stm32l432/build/common.mk index 4170e51..7c0ae32 100644 --- a/targets/stm32l432/build/common.mk +++ b/targets/stm32l432/build/common.mk @@ -6,7 +6,7 @@ AR=$(PREFIX)arm-none-eabi-ar DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \ lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \ lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \ - lib/stm32l4xx_ll_usart.c + lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_spi.c USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \ lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \ diff --git a/targets/stm32l432/lib/stm32l4xx_ll_spi.c b/targets/stm32l432/lib/stm32l4xx_ll_spi.c new file mode 100644 index 0000000..99e28de --- /dev/null +++ b/targets/stm32l432/lib/stm32l4xx_ll_spi.c @@ -0,0 +1,307 @@ +/** + ****************************************************************************** + * @file stm32l4xx_ll_spi.c + * @author MCD Application Team + * @brief SPI LL module driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ +#if defined(USE_FULL_LL_DRIVER) + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx_ll_spi.h" +#include "stm32l4xx_ll_bus.h" + +#ifdef USE_FULL_ASSERT +#include "stm32_assert.h" +#else +#define assert_param(expr) ((void)0U) +#endif + +/** @addtogroup STM32L4xx_LL_Driver + * @{ + */ + +#if defined (SPI1) || defined (SPI2) || defined (SPI3) + +/** @addtogroup SPI_LL + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup SPI_LL_Private_Constants SPI Private Constants + * @{ + */ +/* SPI registers Masks */ +#define SPI_CR1_CLEAR_MASK (SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_MSTR | \ + SPI_CR1_BR | SPI_CR1_LSBFIRST | SPI_CR1_SSI | \ + SPI_CR1_SSM | SPI_CR1_RXONLY | SPI_CR1_CRCL | \ + SPI_CR1_CRCNEXT | SPI_CR1_CRCEN | SPI_CR1_BIDIOE | \ + SPI_CR1_BIDIMODE) +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup SPI_LL_Private_Macros SPI Private Macros + * @{ + */ +#define IS_LL_SPI_TRANSFER_DIRECTION(__VALUE__) (((__VALUE__) == LL_SPI_FULL_DUPLEX) \ + || ((__VALUE__) == LL_SPI_SIMPLEX_RX) \ + || ((__VALUE__) == LL_SPI_HALF_DUPLEX_RX) \ + || ((__VALUE__) == LL_SPI_HALF_DUPLEX_TX)) + +#define IS_LL_SPI_MODE(__VALUE__) (((__VALUE__) == LL_SPI_MODE_MASTER) \ + || ((__VALUE__) == LL_SPI_MODE_SLAVE)) + +#define IS_LL_SPI_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_SPI_DATAWIDTH_4BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_5BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_6BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_7BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_8BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_9BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_10BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_11BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_12BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_13BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_14BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_15BIT) \ + || ((__VALUE__) == LL_SPI_DATAWIDTH_16BIT)) + +#define IS_LL_SPI_POLARITY(__VALUE__) (((__VALUE__) == LL_SPI_POLARITY_LOW) \ + || ((__VALUE__) == LL_SPI_POLARITY_HIGH)) + +#define IS_LL_SPI_PHASE(__VALUE__) (((__VALUE__) == LL_SPI_PHASE_1EDGE) \ + || ((__VALUE__) == LL_SPI_PHASE_2EDGE)) + +#define IS_LL_SPI_NSS(__VALUE__) (((__VALUE__) == LL_SPI_NSS_SOFT) \ + || ((__VALUE__) == LL_SPI_NSS_HARD_INPUT) \ + || ((__VALUE__) == LL_SPI_NSS_HARD_OUTPUT)) + +#define IS_LL_SPI_BAUDRATE(__VALUE__) (((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV2) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV4) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV8) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV16) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV32) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV64) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV128) \ + || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV256)) + +#define IS_LL_SPI_BITORDER(__VALUE__) (((__VALUE__) == LL_SPI_LSB_FIRST) \ + || ((__VALUE__) == LL_SPI_MSB_FIRST)) + +#define IS_LL_SPI_CRCCALCULATION(__VALUE__) (((__VALUE__) == LL_SPI_CRCCALCULATION_ENABLE) \ + || ((__VALUE__) == LL_SPI_CRCCALCULATION_DISABLE)) + +#define IS_LL_SPI_CRC_POLYNOMIAL(__VALUE__) ((__VALUE__) >= 0x1U) + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup SPI_LL_Exported_Functions + * @{ + */ + +/** @addtogroup SPI_LL_EF_Init + * @{ + */ + +/** + * @brief De-initialize the SPI registers to their default reset values. + * @param SPIx SPI Instance + * @retval An ErrorStatus enumeration value: + * - SUCCESS: SPI registers are de-initialized + * - ERROR: SPI registers are not de-initialized + */ +ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx) +{ + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_INSTANCE(SPIx)); + +#if defined(SPI1) + if (SPIx == SPI1) + { + /* Force reset of SPI clock */ + LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); + + /* Release reset of SPI clock */ + LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); + + status = SUCCESS; + } +#endif /* SPI1 */ +#if defined(SPI2) + if (SPIx == SPI2) + { + /* Force reset of SPI clock */ + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); + + /* Release reset of SPI clock */ + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); + + status = SUCCESS; + } +#endif /* SPI2 */ +#if defined(SPI3) + if (SPIx == SPI3) + { + /* Force reset of SPI clock */ + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI3); + + /* Release reset of SPI clock */ + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI3); + + status = SUCCESS; + } +#endif /* SPI3 */ + + return status; +} + +/** + * @brief Initialize the SPI registers according to the specified parameters in SPI_InitStruct. + * @note As some bits in SPI configuration registers can only be written when the SPI is disabled (SPI_CR1_SPE bit =0), + * SPI IP should be in disabled state prior calling this function. Otherwise, ERROR result will be returned. + * @param SPIx SPI Instance + * @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure + * @retval An ErrorStatus enumeration value. (Return always SUCCESS) + */ +ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct) +{ + ErrorStatus status = ERROR; + + /* Check the SPI Instance SPIx*/ + assert_param(IS_SPI_ALL_INSTANCE(SPIx)); + + /* Check the SPI parameters from SPI_InitStruct*/ + assert_param(IS_LL_SPI_TRANSFER_DIRECTION(SPI_InitStruct->TransferDirection)); + assert_param(IS_LL_SPI_MODE(SPI_InitStruct->Mode)); + assert_param(IS_LL_SPI_DATAWIDTH(SPI_InitStruct->DataWidth)); + assert_param(IS_LL_SPI_POLARITY(SPI_InitStruct->ClockPolarity)); + assert_param(IS_LL_SPI_PHASE(SPI_InitStruct->ClockPhase)); + assert_param(IS_LL_SPI_NSS(SPI_InitStruct->NSS)); + assert_param(IS_LL_SPI_BAUDRATE(SPI_InitStruct->BaudRate)); + assert_param(IS_LL_SPI_BITORDER(SPI_InitStruct->BitOrder)); + assert_param(IS_LL_SPI_CRCCALCULATION(SPI_InitStruct->CRCCalculation)); + + if (LL_SPI_IsEnabled(SPIx) == 0x00000000U) + { + /*---------------------------- SPIx CR1 Configuration ------------------------ + * Configure SPIx CR1 with parameters: + * - TransferDirection: SPI_CR1_BIDIMODE, SPI_CR1_BIDIOE and SPI_CR1_RXONLY bits + * - Master/Slave Mode: SPI_CR1_MSTR bit + * - ClockPolarity: SPI_CR1_CPOL bit + * - ClockPhase: SPI_CR1_CPHA bit + * - NSS management: SPI_CR1_SSM bit + * - BaudRate prescaler: SPI_CR1_BR[2:0] bits + * - BitOrder: SPI_CR1_LSBFIRST bit + * - CRCCalculation: SPI_CR1_CRCEN bit + */ + MODIFY_REG(SPIx->CR1, + SPI_CR1_CLEAR_MASK, + SPI_InitStruct->TransferDirection | SPI_InitStruct->Mode | + SPI_InitStruct->ClockPolarity | SPI_InitStruct->ClockPhase | + SPI_InitStruct->NSS | SPI_InitStruct->BaudRate | + SPI_InitStruct->BitOrder | SPI_InitStruct->CRCCalculation); + + /*---------------------------- SPIx CR2 Configuration ------------------------ + * Configure SPIx CR2 with parameters: + * - DataWidth: DS[3:0] bits + * - NSS management: SSOE bit + */ + MODIFY_REG(SPIx->CR2, + SPI_CR2_DS | SPI_CR2_SSOE, + SPI_InitStruct->DataWidth | (SPI_InitStruct->NSS >> 16U)); + + /*---------------------------- SPIx CRCPR Configuration ---------------------- + * Configure SPIx CRCPR with parameters: + * - CRCPoly: CRCPOLY[15:0] bits + */ + if (SPI_InitStruct->CRCCalculation == LL_SPI_CRCCALCULATION_ENABLE) + { + assert_param(IS_LL_SPI_CRC_POLYNOMIAL(SPI_InitStruct->CRCPoly)); + LL_SPI_SetCRCPolynomial(SPIx, SPI_InitStruct->CRCPoly); + } + status = SUCCESS; + } + + return status; +} + +/** + * @brief Set each @ref LL_SPI_InitTypeDef field to default value. + * @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure + * whose fields will be set to default values. + * @retval None + */ +void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct) +{ + /* Set SPI_InitStruct fields to default values */ + SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX; + SPI_InitStruct->Mode = LL_SPI_MODE_SLAVE; + SPI_InitStruct->DataWidth = LL_SPI_DATAWIDTH_8BIT; + SPI_InitStruct->ClockPolarity = LL_SPI_POLARITY_LOW; + SPI_InitStruct->ClockPhase = LL_SPI_PHASE_1EDGE; + SPI_InitStruct->NSS = LL_SPI_NSS_HARD_INPUT; + SPI_InitStruct->BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2; + SPI_InitStruct->BitOrder = LL_SPI_MSB_FIRST; + SPI_InitStruct->CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; + SPI_InitStruct->CRCPoly = 7U; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */ + +/** + * @} + */ + +#endif /* USE_FULL_LL_DRIVER */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/targets/stm32l432/lib/stm32l4xx_ll_spi.h b/targets/stm32l432/lib/stm32l4xx_ll_spi.h new file mode 100644 index 0000000..b5bc17a --- /dev/null +++ b/targets/stm32l432/lib/stm32l4xx_ll_spi.h @@ -0,0 +1,1436 @@ +/** + ****************************************************************************** + * @file stm32l4xx_ll_spi.h + * @author MCD Application Team + * @brief Header file of SPI LL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32L4xx_LL_SPI_H +#define STM32L4xx_LL_SPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx.h" + +/** @addtogroup STM32L4xx_LL_Driver + * @{ + */ + +#if defined (SPI1) || defined (SPI2) || defined (SPI3) + +/** @defgroup SPI_LL SPI + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private macros ------------------------------------------------------------*/ + +/* Exported types ------------------------------------------------------------*/ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup SPI_LL_ES_INIT SPI Exported Init structure + * @{ + */ + +/** + * @brief SPI Init structures definition + */ +typedef struct +{ + uint32_t TransferDirection; /*!< Specifies the SPI unidirectional or bidirectional data mode. + This parameter can be a value of @ref SPI_LL_EC_TRANSFER_MODE. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetTransferDirection().*/ + + uint32_t Mode; /*!< Specifies the SPI mode (Master/Slave). + This parameter can be a value of @ref SPI_LL_EC_MODE. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetMode().*/ + + uint32_t DataWidth; /*!< Specifies the SPI data width. + This parameter can be a value of @ref SPI_LL_EC_DATAWIDTH. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetDataWidth().*/ + + uint32_t ClockPolarity; /*!< Specifies the serial clock steady state. + This parameter can be a value of @ref SPI_LL_EC_POLARITY. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetClockPolarity().*/ + + uint32_t ClockPhase; /*!< Specifies the clock active edge for the bit capture. + This parameter can be a value of @ref SPI_LL_EC_PHASE. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetClockPhase().*/ + + uint32_t NSS; /*!< Specifies whether the NSS signal is managed by hardware (NSS pin) or by software using the SSI bit. + This parameter can be a value of @ref SPI_LL_EC_NSS_MODE. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetNSSMode().*/ + + uint32_t BaudRate; /*!< Specifies the BaudRate prescaler value which will be used to configure the transmit and receive SCK clock. + This parameter can be a value of @ref SPI_LL_EC_BAUDRATEPRESCALER. + @note The communication clock is derived from the master clock. The slave clock does not need to be set. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetBaudRatePrescaler().*/ + + uint32_t BitOrder; /*!< Specifies whether data transfers start from MSB or LSB bit. + This parameter can be a value of @ref SPI_LL_EC_BIT_ORDER. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetTransferBitOrder().*/ + + uint32_t CRCCalculation; /*!< Specifies if the CRC calculation is enabled or not. + This parameter can be a value of @ref SPI_LL_EC_CRC_CALCULATION. + + This feature can be modified afterwards using unitary functions @ref LL_SPI_EnableCRC() and @ref LL_SPI_DisableCRC().*/ + + uint32_t CRCPoly; /*!< Specifies the polynomial used for the CRC calculation. + This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFFFF. + + This feature can be modified afterwards using unitary function @ref LL_SPI_SetCRCPolynomial().*/ + +} LL_SPI_InitTypeDef; + +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup SPI_LL_Exported_Constants SPI Exported Constants + * @{ + */ + +/** @defgroup SPI_LL_EC_GET_FLAG Get Flags Defines + * @brief Flags defines which can be used with LL_SPI_ReadReg function + * @{ + */ +#define LL_SPI_SR_RXNE SPI_SR_RXNE /*!< Rx buffer not empty flag */ +#define LL_SPI_SR_TXE SPI_SR_TXE /*!< Tx buffer empty flag */ +#define LL_SPI_SR_BSY SPI_SR_BSY /*!< Busy flag */ +#define LL_SPI_SR_CRCERR SPI_SR_CRCERR /*!< CRC error flag */ +#define LL_SPI_SR_MODF SPI_SR_MODF /*!< Mode fault flag */ +#define LL_SPI_SR_OVR SPI_SR_OVR /*!< Overrun flag */ +#define LL_SPI_SR_FRE SPI_SR_FRE /*!< TI mode frame format error flag */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_IT IT Defines + * @brief IT defines which can be used with LL_SPI_ReadReg and LL_SPI_WriteReg functions + * @{ + */ +#define LL_SPI_CR2_RXNEIE SPI_CR2_RXNEIE /*!< Rx buffer not empty interrupt enable */ +#define LL_SPI_CR2_TXEIE SPI_CR2_TXEIE /*!< Tx buffer empty interrupt enable */ +#define LL_SPI_CR2_ERRIE SPI_CR2_ERRIE /*!< Error interrupt enable */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_MODE Operation Mode + * @{ + */ +#define LL_SPI_MODE_MASTER (SPI_CR1_MSTR | SPI_CR1_SSI) /*!< Master configuration */ +#define LL_SPI_MODE_SLAVE 0x00000000U /*!< Slave configuration */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_PROTOCOL Serial Protocol + * @{ + */ +#define LL_SPI_PROTOCOL_MOTOROLA 0x00000000U /*!< Motorola mode. Used as default value */ +#define LL_SPI_PROTOCOL_TI (SPI_CR2_FRF) /*!< TI mode */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_PHASE Clock Phase + * @{ + */ +#define LL_SPI_PHASE_1EDGE 0x00000000U /*!< First clock transition is the first data capture edge */ +#define LL_SPI_PHASE_2EDGE (SPI_CR1_CPHA) /*!< Second clock transition is the first data capture edge */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_POLARITY Clock Polarity + * @{ + */ +#define LL_SPI_POLARITY_LOW 0x00000000U /*!< Clock to 0 when idle */ +#define LL_SPI_POLARITY_HIGH (SPI_CR1_CPOL) /*!< Clock to 1 when idle */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_BAUDRATEPRESCALER Baud Rate Prescaler + * @{ + */ +#define LL_SPI_BAUDRATEPRESCALER_DIV2 0x00000000U /*!< BaudRate control equal to fPCLK/2 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV4 (SPI_CR1_BR_0) /*!< BaudRate control equal to fPCLK/4 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV8 (SPI_CR1_BR_1) /*!< BaudRate control equal to fPCLK/8 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV16 (SPI_CR1_BR_1 | SPI_CR1_BR_0) /*!< BaudRate control equal to fPCLK/16 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV32 (SPI_CR1_BR_2) /*!< BaudRate control equal to fPCLK/32 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV64 (SPI_CR1_BR_2 | SPI_CR1_BR_0) /*!< BaudRate control equal to fPCLK/64 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV128 (SPI_CR1_BR_2 | SPI_CR1_BR_1) /*!< BaudRate control equal to fPCLK/128 */ +#define LL_SPI_BAUDRATEPRESCALER_DIV256 (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0) /*!< BaudRate control equal to fPCLK/256 */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_BIT_ORDER Transmission Bit Order + * @{ + */ +#define LL_SPI_LSB_FIRST (SPI_CR1_LSBFIRST) /*!< Data is transmitted/received with the LSB first */ +#define LL_SPI_MSB_FIRST 0x00000000U /*!< Data is transmitted/received with the MSB first */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_TRANSFER_MODE Transfer Mode + * @{ + */ +#define LL_SPI_FULL_DUPLEX 0x00000000U /*!< Full-Duplex mode. Rx and Tx transfer on 2 lines */ +#define LL_SPI_SIMPLEX_RX (SPI_CR1_RXONLY) /*!< Simplex Rx mode. Rx transfer only on 1 line */ +#define LL_SPI_HALF_DUPLEX_RX (SPI_CR1_BIDIMODE) /*!< Half-Duplex Rx mode. Rx transfer on 1 line */ +#define LL_SPI_HALF_DUPLEX_TX (SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE) /*!< Half-Duplex Tx mode. Tx transfer on 1 line */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_NSS_MODE Slave Select Pin Mode + * @{ + */ +#define LL_SPI_NSS_SOFT (SPI_CR1_SSM) /*!< NSS managed internally. NSS pin not used and free */ +#define LL_SPI_NSS_HARD_INPUT 0x00000000U /*!< NSS pin used in Input. Only used in Master mode */ +#define LL_SPI_NSS_HARD_OUTPUT (((uint32_t)SPI_CR2_SSOE << 16U)) /*!< NSS pin used in Output. Only used in Slave mode as chip select */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_DATAWIDTH Datawidth + * @{ + */ +#define LL_SPI_DATAWIDTH_4BIT (SPI_CR2_DS_0 | SPI_CR2_DS_1) /*!< Data length for SPI transfer: 4 bits */ +#define LL_SPI_DATAWIDTH_5BIT (SPI_CR2_DS_2) /*!< Data length for SPI transfer: 5 bits */ +#define LL_SPI_DATAWIDTH_6BIT (SPI_CR2_DS_2 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 6 bits */ +#define LL_SPI_DATAWIDTH_7BIT (SPI_CR2_DS_2 | SPI_CR2_DS_1) /*!< Data length for SPI transfer: 7 bits */ +#define LL_SPI_DATAWIDTH_8BIT (SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 8 bits */ +#define LL_SPI_DATAWIDTH_9BIT (SPI_CR2_DS_3) /*!< Data length for SPI transfer: 9 bits */ +#define LL_SPI_DATAWIDTH_10BIT (SPI_CR2_DS_3 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 10 bits */ +#define LL_SPI_DATAWIDTH_11BIT (SPI_CR2_DS_3 | SPI_CR2_DS_1) /*!< Data length for SPI transfer: 11 bits */ +#define LL_SPI_DATAWIDTH_12BIT (SPI_CR2_DS_3 | SPI_CR2_DS_1 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 12 bits */ +#define LL_SPI_DATAWIDTH_13BIT (SPI_CR2_DS_3 | SPI_CR2_DS_2) /*!< Data length for SPI transfer: 13 bits */ +#define LL_SPI_DATAWIDTH_14BIT (SPI_CR2_DS_3 | SPI_CR2_DS_2 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 14 bits */ +#define LL_SPI_DATAWIDTH_15BIT (SPI_CR2_DS_3 | SPI_CR2_DS_2 | SPI_CR2_DS_1) /*!< Data length for SPI transfer: 15 bits */ +#define LL_SPI_DATAWIDTH_16BIT (SPI_CR2_DS_3 | SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0) /*!< Data length for SPI transfer: 16 bits */ +/** + * @} + */ +#if defined(USE_FULL_LL_DRIVER) + +/** @defgroup SPI_LL_EC_CRC_CALCULATION CRC Calculation + * @{ + */ +#define LL_SPI_CRCCALCULATION_DISABLE 0x00000000U /*!< CRC calculation disabled */ +#define LL_SPI_CRCCALCULATION_ENABLE (SPI_CR1_CRCEN) /*!< CRC calculation enabled */ +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** @defgroup SPI_LL_EC_CRC_LENGTH CRC Length + * @{ + */ +#define LL_SPI_CRC_8BIT 0x00000000U /*!< 8-bit CRC length */ +#define LL_SPI_CRC_16BIT (SPI_CR1_CRCL) /*!< 16-bit CRC length */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_RX_FIFO_TH RX FIFO Threshold + * @{ + */ +#define LL_SPI_RX_FIFO_TH_HALF 0x00000000U /*!< RXNE event is generated if FIFO level is greater than or equel to 1/2 (16-bit) */ +#define LL_SPI_RX_FIFO_TH_QUARTER (SPI_CR2_FRXTH) /*!< RXNE event is generated if FIFO level is greater than or equel to 1/4 (8-bit) */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_RX_FIFO RX FIFO Level + * @{ + */ +#define LL_SPI_RX_FIFO_EMPTY 0x00000000U /*!< FIFO reception empty */ +#define LL_SPI_RX_FIFO_QUARTER_FULL (SPI_SR_FRLVL_0) /*!< FIFO reception 1/4 */ +#define LL_SPI_RX_FIFO_HALF_FULL (SPI_SR_FRLVL_1) /*!< FIFO reception 1/2 */ +#define LL_SPI_RX_FIFO_FULL (SPI_SR_FRLVL_1 | SPI_SR_FRLVL_0) /*!< FIFO reception full */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_TX_FIFO TX FIFO Level + * @{ + */ +#define LL_SPI_TX_FIFO_EMPTY 0x00000000U /*!< FIFO transmission empty */ +#define LL_SPI_TX_FIFO_QUARTER_FULL (SPI_SR_FTLVL_0) /*!< FIFO transmission 1/4 */ +#define LL_SPI_TX_FIFO_HALF_FULL (SPI_SR_FTLVL_1) /*!< FIFO transmission 1/2 */ +#define LL_SPI_TX_FIFO_FULL (SPI_SR_FTLVL_1 | SPI_SR_FTLVL_0) /*!< FIFO transmission full */ +/** + * @} + */ + +/** @defgroup SPI_LL_EC_DMA_PARITY DMA Parity + * @{ + */ +#define LL_SPI_DMA_PARITY_EVEN 0x00000000U /*!< Select DMA parity Even */ +#define LL_SPI_DMA_PARITY_ODD 0x00000001U /*!< Select DMA parity Odd */ + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup SPI_LL_Exported_Macros SPI Exported Macros + * @{ + */ + +/** @defgroup SPI_LL_EM_WRITE_READ Common Write and read registers Macros + * @{ + */ + +/** + * @brief Write a value in SPI register + * @param __INSTANCE__ SPI Instance + * @param __REG__ Register to be written + * @param __VALUE__ Value to be written in the register + * @retval None + */ +#define LL_SPI_WriteReg(__INSTANCE__, __REG__, __VALUE__) WRITE_REG(__INSTANCE__->__REG__, (__VALUE__)) + +/** + * @brief Read a value in SPI register + * @param __INSTANCE__ SPI Instance + * @param __REG__ Register to be read + * @retval Register value + */ +#define LL_SPI_ReadReg(__INSTANCE__, __REG__) READ_REG(__INSTANCE__->__REG__) +/** + * @} + */ + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup SPI_LL_Exported_Functions SPI Exported Functions + * @{ + */ + +/** @defgroup SPI_LL_EF_Configuration Configuration + * @{ + */ + +/** + * @brief Enable SPI peripheral + * @rmtoll CR1 SPE LL_SPI_Enable + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_Enable(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR1, SPI_CR1_SPE); +} + +/** + * @brief Disable SPI peripheral + * @note When disabling the SPI, follow the procedure described in the Reference Manual. + * @rmtoll CR1 SPE LL_SPI_Disable + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_Disable(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR1, SPI_CR1_SPE); +} + +/** + * @brief Check if SPI peripheral is enabled + * @rmtoll CR1 SPE LL_SPI_IsEnabled + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabled(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR1, SPI_CR1_SPE) == (SPI_CR1_SPE)) ? 1UL : 0UL); +} + +/** + * @brief Set SPI operation mode to Master or Slave + * @note This bit should not be changed when communication is ongoing. + * @rmtoll CR1 MSTR LL_SPI_SetMode\n + * CR1 SSI LL_SPI_SetMode + * @param SPIx SPI Instance + * @param Mode This parameter can be one of the following values: + * @arg @ref LL_SPI_MODE_MASTER + * @arg @ref LL_SPI_MODE_SLAVE + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetMode(SPI_TypeDef *SPIx, uint32_t Mode) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_MSTR | SPI_CR1_SSI, Mode); +} + +/** + * @brief Get SPI operation mode (Master or Slave) + * @rmtoll CR1 MSTR LL_SPI_GetMode\n + * CR1 SSI LL_SPI_GetMode + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_MODE_MASTER + * @arg @ref LL_SPI_MODE_SLAVE + */ +__STATIC_INLINE uint32_t LL_SPI_GetMode(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_MSTR | SPI_CR1_SSI)); +} + +/** + * @brief Set serial protocol used + * @note This bit should be written only when SPI is disabled (SPE = 0) for correct operation. + * @rmtoll CR2 FRF LL_SPI_SetStandard + * @param SPIx SPI Instance + * @param Standard This parameter can be one of the following values: + * @arg @ref LL_SPI_PROTOCOL_MOTOROLA + * @arg @ref LL_SPI_PROTOCOL_TI + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetStandard(SPI_TypeDef *SPIx, uint32_t Standard) +{ + MODIFY_REG(SPIx->CR2, SPI_CR2_FRF, Standard); +} + +/** + * @brief Get serial protocol used + * @rmtoll CR2 FRF LL_SPI_GetStandard + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_PROTOCOL_MOTOROLA + * @arg @ref LL_SPI_PROTOCOL_TI + */ +__STATIC_INLINE uint32_t LL_SPI_GetStandard(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR2, SPI_CR2_FRF)); +} + +/** + * @brief Set clock phase + * @note This bit should not be changed when communication is ongoing. + * This bit is not used in SPI TI mode. + * @rmtoll CR1 CPHA LL_SPI_SetClockPhase + * @param SPIx SPI Instance + * @param ClockPhase This parameter can be one of the following values: + * @arg @ref LL_SPI_PHASE_1EDGE + * @arg @ref LL_SPI_PHASE_2EDGE + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetClockPhase(SPI_TypeDef *SPIx, uint32_t ClockPhase) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_CPHA, ClockPhase); +} + +/** + * @brief Get clock phase + * @rmtoll CR1 CPHA LL_SPI_GetClockPhase + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_PHASE_1EDGE + * @arg @ref LL_SPI_PHASE_2EDGE + */ +__STATIC_INLINE uint32_t LL_SPI_GetClockPhase(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_CPHA)); +} + +/** + * @brief Set clock polarity + * @note This bit should not be changed when communication is ongoing. + * This bit is not used in SPI TI mode. + * @rmtoll CR1 CPOL LL_SPI_SetClockPolarity + * @param SPIx SPI Instance + * @param ClockPolarity This parameter can be one of the following values: + * @arg @ref LL_SPI_POLARITY_LOW + * @arg @ref LL_SPI_POLARITY_HIGH + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetClockPolarity(SPI_TypeDef *SPIx, uint32_t ClockPolarity) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_CPOL, ClockPolarity); +} + +/** + * @brief Get clock polarity + * @rmtoll CR1 CPOL LL_SPI_GetClockPolarity + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_POLARITY_LOW + * @arg @ref LL_SPI_POLARITY_HIGH + */ +__STATIC_INLINE uint32_t LL_SPI_GetClockPolarity(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_CPOL)); +} + +/** + * @brief Set baud rate prescaler + * @note These bits should not be changed when communication is ongoing. SPI BaudRate = fPCLK/Prescaler. + * @rmtoll CR1 BR LL_SPI_SetBaudRatePrescaler + * @param SPIx SPI Instance + * @param BaudRate This parameter can be one of the following values: + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV2 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV4 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV8 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV16 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV32 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV64 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV128 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV256 + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetBaudRatePrescaler(SPI_TypeDef *SPIx, uint32_t BaudRate) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_BR, BaudRate); +} + +/** + * @brief Get baud rate prescaler + * @rmtoll CR1 BR LL_SPI_GetBaudRatePrescaler + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV2 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV4 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV8 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV16 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV32 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV64 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV128 + * @arg @ref LL_SPI_BAUDRATEPRESCALER_DIV256 + */ +__STATIC_INLINE uint32_t LL_SPI_GetBaudRatePrescaler(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_BR)); +} + +/** + * @brief Set transfer bit order + * @note This bit should not be changed when communication is ongoing. This bit is not used in SPI TI mode. + * @rmtoll CR1 LSBFIRST LL_SPI_SetTransferBitOrder + * @param SPIx SPI Instance + * @param BitOrder This parameter can be one of the following values: + * @arg @ref LL_SPI_LSB_FIRST + * @arg @ref LL_SPI_MSB_FIRST + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetTransferBitOrder(SPI_TypeDef *SPIx, uint32_t BitOrder) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_LSBFIRST, BitOrder); +} + +/** + * @brief Get transfer bit order + * @rmtoll CR1 LSBFIRST LL_SPI_GetTransferBitOrder + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_LSB_FIRST + * @arg @ref LL_SPI_MSB_FIRST + */ +__STATIC_INLINE uint32_t LL_SPI_GetTransferBitOrder(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_LSBFIRST)); +} + +/** + * @brief Set transfer direction mode + * @note For Half-Duplex mode, Rx Direction is set by default. + * In master mode, the MOSI pin is used and in slave mode, the MISO pin is used for Half-Duplex. + * @rmtoll CR1 RXONLY LL_SPI_SetTransferDirection\n + * CR1 BIDIMODE LL_SPI_SetTransferDirection\n + * CR1 BIDIOE LL_SPI_SetTransferDirection + * @param SPIx SPI Instance + * @param TransferDirection This parameter can be one of the following values: + * @arg @ref LL_SPI_FULL_DUPLEX + * @arg @ref LL_SPI_SIMPLEX_RX + * @arg @ref LL_SPI_HALF_DUPLEX_RX + * @arg @ref LL_SPI_HALF_DUPLEX_TX + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetTransferDirection(SPI_TypeDef *SPIx, uint32_t TransferDirection) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_RXONLY | SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE, TransferDirection); +} + +/** + * @brief Get transfer direction mode + * @rmtoll CR1 RXONLY LL_SPI_GetTransferDirection\n + * CR1 BIDIMODE LL_SPI_GetTransferDirection\n + * CR1 BIDIOE LL_SPI_GetTransferDirection + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_FULL_DUPLEX + * @arg @ref LL_SPI_SIMPLEX_RX + * @arg @ref LL_SPI_HALF_DUPLEX_RX + * @arg @ref LL_SPI_HALF_DUPLEX_TX + */ +__STATIC_INLINE uint32_t LL_SPI_GetTransferDirection(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_RXONLY | SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE)); +} + +/** + * @brief Set frame data width + * @rmtoll CR2 DS LL_SPI_SetDataWidth + * @param SPIx SPI Instance + * @param DataWidth This parameter can be one of the following values: + * @arg @ref LL_SPI_DATAWIDTH_4BIT + * @arg @ref LL_SPI_DATAWIDTH_5BIT + * @arg @ref LL_SPI_DATAWIDTH_6BIT + * @arg @ref LL_SPI_DATAWIDTH_7BIT + * @arg @ref LL_SPI_DATAWIDTH_8BIT + * @arg @ref LL_SPI_DATAWIDTH_9BIT + * @arg @ref LL_SPI_DATAWIDTH_10BIT + * @arg @ref LL_SPI_DATAWIDTH_11BIT + * @arg @ref LL_SPI_DATAWIDTH_12BIT + * @arg @ref LL_SPI_DATAWIDTH_13BIT + * @arg @ref LL_SPI_DATAWIDTH_14BIT + * @arg @ref LL_SPI_DATAWIDTH_15BIT + * @arg @ref LL_SPI_DATAWIDTH_16BIT + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetDataWidth(SPI_TypeDef *SPIx, uint32_t DataWidth) +{ + MODIFY_REG(SPIx->CR2, SPI_CR2_DS, DataWidth); +} + +/** + * @brief Get frame data width + * @rmtoll CR2 DS LL_SPI_GetDataWidth + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_DATAWIDTH_4BIT + * @arg @ref LL_SPI_DATAWIDTH_5BIT + * @arg @ref LL_SPI_DATAWIDTH_6BIT + * @arg @ref LL_SPI_DATAWIDTH_7BIT + * @arg @ref LL_SPI_DATAWIDTH_8BIT + * @arg @ref LL_SPI_DATAWIDTH_9BIT + * @arg @ref LL_SPI_DATAWIDTH_10BIT + * @arg @ref LL_SPI_DATAWIDTH_11BIT + * @arg @ref LL_SPI_DATAWIDTH_12BIT + * @arg @ref LL_SPI_DATAWIDTH_13BIT + * @arg @ref LL_SPI_DATAWIDTH_14BIT + * @arg @ref LL_SPI_DATAWIDTH_15BIT + * @arg @ref LL_SPI_DATAWIDTH_16BIT + */ +__STATIC_INLINE uint32_t LL_SPI_GetDataWidth(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR2, SPI_CR2_DS)); +} + +/** + * @brief Set threshold of RXFIFO that triggers an RXNE event + * @rmtoll CR2 FRXTH LL_SPI_SetRxFIFOThreshold + * @param SPIx SPI Instance + * @param Threshold This parameter can be one of the following values: + * @arg @ref LL_SPI_RX_FIFO_TH_HALF + * @arg @ref LL_SPI_RX_FIFO_TH_QUARTER + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetRxFIFOThreshold(SPI_TypeDef *SPIx, uint32_t Threshold) +{ + MODIFY_REG(SPIx->CR2, SPI_CR2_FRXTH, Threshold); +} + +/** + * @brief Get threshold of RXFIFO that triggers an RXNE event + * @rmtoll CR2 FRXTH LL_SPI_GetRxFIFOThreshold + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_RX_FIFO_TH_HALF + * @arg @ref LL_SPI_RX_FIFO_TH_QUARTER + */ +__STATIC_INLINE uint32_t LL_SPI_GetRxFIFOThreshold(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR2, SPI_CR2_FRXTH)); +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_CRC_Management CRC Management + * @{ + */ + +/** + * @brief Enable CRC + * @note This bit should be written only when SPI is disabled (SPE = 0) for correct operation. + * @rmtoll CR1 CRCEN LL_SPI_EnableCRC + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableCRC(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR1, SPI_CR1_CRCEN); +} + +/** + * @brief Disable CRC + * @note This bit should be written only when SPI is disabled (SPE = 0) for correct operation. + * @rmtoll CR1 CRCEN LL_SPI_DisableCRC + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableCRC(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR1, SPI_CR1_CRCEN); +} + +/** + * @brief Check if CRC is enabled + * @note This bit should be written only when SPI is disabled (SPE = 0) for correct operation. + * @rmtoll CR1 CRCEN LL_SPI_IsEnabledCRC + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledCRC(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR1, SPI_CR1_CRCEN) == (SPI_CR1_CRCEN)) ? 1UL : 0UL); +} + +/** + * @brief Set CRC Length + * @note This bit should be written only when SPI is disabled (SPE = 0) for correct operation. + * @rmtoll CR1 CRCL LL_SPI_SetCRCWidth + * @param SPIx SPI Instance + * @param CRCLength This parameter can be one of the following values: + * @arg @ref LL_SPI_CRC_8BIT + * @arg @ref LL_SPI_CRC_16BIT + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetCRCWidth(SPI_TypeDef *SPIx, uint32_t CRCLength) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_CRCL, CRCLength); +} + +/** + * @brief Get CRC Length + * @rmtoll CR1 CRCL LL_SPI_GetCRCWidth + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_CRC_8BIT + * @arg @ref LL_SPI_CRC_16BIT + */ +__STATIC_INLINE uint32_t LL_SPI_GetCRCWidth(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR1, SPI_CR1_CRCL)); +} + +/** + * @brief Set CRCNext to transfer CRC on the line + * @note This bit has to be written as soon as the last data is written in the SPIx_DR register. + * @rmtoll CR1 CRCNEXT LL_SPI_SetCRCNext + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetCRCNext(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR1, SPI_CR1_CRCNEXT); +} + +/** + * @brief Set polynomial for CRC calculation + * @rmtoll CRCPR CRCPOLY LL_SPI_SetCRCPolynomial + * @param SPIx SPI Instance + * @param CRCPoly This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFFFF + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetCRCPolynomial(SPI_TypeDef *SPIx, uint32_t CRCPoly) +{ + WRITE_REG(SPIx->CRCPR, (uint16_t)CRCPoly); +} + +/** + * @brief Get polynomial for CRC calculation + * @rmtoll CRCPR CRCPOLY LL_SPI_GetCRCPolynomial + * @param SPIx SPI Instance + * @retval Returned value is a number between Min_Data = 0x00 and Max_Data = 0xFFFF + */ +__STATIC_INLINE uint32_t LL_SPI_GetCRCPolynomial(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_REG(SPIx->CRCPR)); +} + +/** + * @brief Get Rx CRC + * @rmtoll RXCRCR RXCRC LL_SPI_GetRxCRC + * @param SPIx SPI Instance + * @retval Returned value is a number between Min_Data = 0x00 and Max_Data = 0xFFFF + */ +__STATIC_INLINE uint32_t LL_SPI_GetRxCRC(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_REG(SPIx->RXCRCR)); +} + +/** + * @brief Get Tx CRC + * @rmtoll TXCRCR TXCRC LL_SPI_GetTxCRC + * @param SPIx SPI Instance + * @retval Returned value is a number between Min_Data = 0x00 and Max_Data = 0xFFFF + */ +__STATIC_INLINE uint32_t LL_SPI_GetTxCRC(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_REG(SPIx->TXCRCR)); +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_NSS_Management Slave Select Pin Management + * @{ + */ + +/** + * @brief Set NSS mode + * @note LL_SPI_NSS_SOFT Mode is not used in SPI TI mode. + * @rmtoll CR1 SSM LL_SPI_SetNSSMode\n + * @rmtoll CR2 SSOE LL_SPI_SetNSSMode + * @param SPIx SPI Instance + * @param NSS This parameter can be one of the following values: + * @arg @ref LL_SPI_NSS_SOFT + * @arg @ref LL_SPI_NSS_HARD_INPUT + * @arg @ref LL_SPI_NSS_HARD_OUTPUT + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetNSSMode(SPI_TypeDef *SPIx, uint32_t NSS) +{ + MODIFY_REG(SPIx->CR1, SPI_CR1_SSM, NSS); + MODIFY_REG(SPIx->CR2, SPI_CR2_SSOE, ((uint32_t)(NSS >> 16U))); +} + +/** + * @brief Get NSS mode + * @rmtoll CR1 SSM LL_SPI_GetNSSMode\n + * @rmtoll CR2 SSOE LL_SPI_GetNSSMode + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_NSS_SOFT + * @arg @ref LL_SPI_NSS_HARD_INPUT + * @arg @ref LL_SPI_NSS_HARD_OUTPUT + */ +__STATIC_INLINE uint32_t LL_SPI_GetNSSMode(SPI_TypeDef *SPIx) +{ + register uint32_t Ssm = (READ_BIT(SPIx->CR1, SPI_CR1_SSM)); + register uint32_t Ssoe = (READ_BIT(SPIx->CR2, SPI_CR2_SSOE) << 16U); + return (Ssm | Ssoe); +} + +/** + * @brief Enable NSS pulse management + * @note This bit should not be changed when communication is ongoing. This bit is not used in SPI TI mode. + * @rmtoll CR2 NSSP LL_SPI_EnableNSSPulseMgt + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableNSSPulseMgt(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_NSSP); +} + +/** + * @brief Disable NSS pulse management + * @note This bit should not be changed when communication is ongoing. This bit is not used in SPI TI mode. + * @rmtoll CR2 NSSP LL_SPI_DisableNSSPulseMgt + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableNSSPulseMgt(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_NSSP); +} + +/** + * @brief Check if NSS pulse is enabled + * @note This bit should not be changed when communication is ongoing. This bit is not used in SPI TI mode. + * @rmtoll CR2 NSSP LL_SPI_IsEnabledNSSPulse + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledNSSPulse(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_NSSP) == (SPI_CR2_NSSP)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_FLAG_Management FLAG Management + * @{ + */ + +/** + * @brief Check if Rx buffer is not empty + * @rmtoll SR RXNE LL_SPI_IsActiveFlag_RXNE + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_RXNE(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_RXNE) == (SPI_SR_RXNE)) ? 1UL : 0UL); +} + +/** + * @brief Check if Tx buffer is empty + * @rmtoll SR TXE LL_SPI_IsActiveFlag_TXE + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_TXE(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_TXE) == (SPI_SR_TXE)) ? 1UL : 0UL); +} + +/** + * @brief Get CRC error flag + * @rmtoll SR CRCERR LL_SPI_IsActiveFlag_CRCERR + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_CRCERR(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_CRCERR) == (SPI_SR_CRCERR)) ? 1UL : 0UL); +} + +/** + * @brief Get mode fault error flag + * @rmtoll SR MODF LL_SPI_IsActiveFlag_MODF + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_MODF(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_MODF) == (SPI_SR_MODF)) ? 1UL : 0UL); +} + +/** + * @brief Get overrun error flag + * @rmtoll SR OVR LL_SPI_IsActiveFlag_OVR + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_OVR(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_OVR) == (SPI_SR_OVR)) ? 1UL : 0UL); +} + +/** + * @brief Get busy flag + * @note The BSY flag is cleared under any one of the following conditions: + * -When the SPI is correctly disabled + * -When a fault is detected in Master mode (MODF bit set to 1) + * -In Master mode, when it finishes a data transmission and no new data is ready to be + * sent + * -In Slave mode, when the BSY flag is set to '0' for at least one SPI clock cycle between + * each data transfer. + * @rmtoll SR BSY LL_SPI_IsActiveFlag_BSY + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_BSY(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_BSY) == (SPI_SR_BSY)) ? 1UL : 0UL); +} + +/** + * @brief Get frame format error flag + * @rmtoll SR FRE LL_SPI_IsActiveFlag_FRE + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_FRE(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->SR, SPI_SR_FRE) == (SPI_SR_FRE)) ? 1UL : 0UL); +} + +/** + * @brief Get FIFO reception Level + * @rmtoll SR FRLVL LL_SPI_GetRxFIFOLevel + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_RX_FIFO_EMPTY + * @arg @ref LL_SPI_RX_FIFO_QUARTER_FULL + * @arg @ref LL_SPI_RX_FIFO_HALF_FULL + * @arg @ref LL_SPI_RX_FIFO_FULL + */ +__STATIC_INLINE uint32_t LL_SPI_GetRxFIFOLevel(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->SR, SPI_SR_FRLVL)); +} + +/** + * @brief Get FIFO Transmission Level + * @rmtoll SR FTLVL LL_SPI_GetTxFIFOLevel + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_TX_FIFO_EMPTY + * @arg @ref LL_SPI_TX_FIFO_QUARTER_FULL + * @arg @ref LL_SPI_TX_FIFO_HALF_FULL + * @arg @ref LL_SPI_TX_FIFO_FULL + */ +__STATIC_INLINE uint32_t LL_SPI_GetTxFIFOLevel(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->SR, SPI_SR_FTLVL)); +} + +/** + * @brief Clear CRC error flag + * @rmtoll SR CRCERR LL_SPI_ClearFlag_CRCERR + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_ClearFlag_CRCERR(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->SR, SPI_SR_CRCERR); +} + +/** + * @brief Clear mode fault error flag + * @note Clearing this flag is done by a read access to the SPIx_SR + * register followed by a write access to the SPIx_CR1 register + * @rmtoll SR MODF LL_SPI_ClearFlag_MODF + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_ClearFlag_MODF(SPI_TypeDef *SPIx) +{ + __IO uint32_t tmpreg_sr; + tmpreg_sr = SPIx->SR; + (void) tmpreg_sr; + CLEAR_BIT(SPIx->CR1, SPI_CR1_SPE); +} + +/** + * @brief Clear overrun error flag + * @note Clearing this flag is done by a read access to the SPIx_DR + * register followed by a read access to the SPIx_SR register + * @rmtoll SR OVR LL_SPI_ClearFlag_OVR + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_ClearFlag_OVR(SPI_TypeDef *SPIx) +{ + __IO uint32_t tmpreg; + tmpreg = SPIx->DR; + (void) tmpreg; + tmpreg = SPIx->SR; + (void) tmpreg; +} + +/** + * @brief Clear frame format error flag + * @note Clearing this flag is done by reading SPIx_SR register + * @rmtoll SR FRE LL_SPI_ClearFlag_FRE + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_ClearFlag_FRE(SPI_TypeDef *SPIx) +{ + __IO uint32_t tmpreg; + tmpreg = SPIx->SR; + (void) tmpreg; +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_IT_Management Interrupt Management + * @{ + */ + +/** + * @brief Enable error interrupt + * @note This bit controls the generation of an interrupt when an error condition occurs (CRCERR, OVR, MODF in SPI mode, FRE at TI mode). + * @rmtoll CR2 ERRIE LL_SPI_EnableIT_ERR + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableIT_ERR(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_ERRIE); +} + +/** + * @brief Enable Rx buffer not empty interrupt + * @rmtoll CR2 RXNEIE LL_SPI_EnableIT_RXNE + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableIT_RXNE(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_RXNEIE); +} + +/** + * @brief Enable Tx buffer empty interrupt + * @rmtoll CR2 TXEIE LL_SPI_EnableIT_TXE + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableIT_TXE(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_TXEIE); +} + +/** + * @brief Disable error interrupt + * @note This bit controls the generation of an interrupt when an error condition occurs (CRCERR, OVR, MODF in SPI mode, FRE at TI mode). + * @rmtoll CR2 ERRIE LL_SPI_DisableIT_ERR + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableIT_ERR(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_ERRIE); +} + +/** + * @brief Disable Rx buffer not empty interrupt + * @rmtoll CR2 RXNEIE LL_SPI_DisableIT_RXNE + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableIT_RXNE(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_RXNEIE); +} + +/** + * @brief Disable Tx buffer empty interrupt + * @rmtoll CR2 TXEIE LL_SPI_DisableIT_TXE + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableIT_TXE(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_TXEIE); +} + +/** + * @brief Check if error interrupt is enabled + * @rmtoll CR2 ERRIE LL_SPI_IsEnabledIT_ERR + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_ERR(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_ERRIE) == (SPI_CR2_ERRIE)) ? 1UL : 0UL); +} + +/** + * @brief Check if Rx buffer not empty interrupt is enabled + * @rmtoll CR2 RXNEIE LL_SPI_IsEnabledIT_RXNE + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_RXNE(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_RXNEIE) == (SPI_CR2_RXNEIE)) ? 1UL : 0UL); +} + +/** + * @brief Check if Tx buffer empty interrupt + * @rmtoll CR2 TXEIE LL_SPI_IsEnabledIT_TXE + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_TXE(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_TXEIE) == (SPI_CR2_TXEIE)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_DMA_Management DMA Management + * @{ + */ + +/** + * @brief Enable DMA Rx + * @rmtoll CR2 RXDMAEN LL_SPI_EnableDMAReq_RX + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableDMAReq_RX(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_RXDMAEN); +} + +/** + * @brief Disable DMA Rx + * @rmtoll CR2 RXDMAEN LL_SPI_DisableDMAReq_RX + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableDMAReq_RX(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_RXDMAEN); +} + +/** + * @brief Check if DMA Rx is enabled + * @rmtoll CR2 RXDMAEN LL_SPI_IsEnabledDMAReq_RX + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledDMAReq_RX(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_RXDMAEN) == (SPI_CR2_RXDMAEN)) ? 1UL : 0UL); +} + +/** + * @brief Enable DMA Tx + * @rmtoll CR2 TXDMAEN LL_SPI_EnableDMAReq_TX + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_EnableDMAReq_TX(SPI_TypeDef *SPIx) +{ + SET_BIT(SPIx->CR2, SPI_CR2_TXDMAEN); +} + +/** + * @brief Disable DMA Tx + * @rmtoll CR2 TXDMAEN LL_SPI_DisableDMAReq_TX + * @param SPIx SPI Instance + * @retval None + */ +__STATIC_INLINE void LL_SPI_DisableDMAReq_TX(SPI_TypeDef *SPIx) +{ + CLEAR_BIT(SPIx->CR2, SPI_CR2_TXDMAEN); +} + +/** + * @brief Check if DMA Tx is enabled + * @rmtoll CR2 TXDMAEN LL_SPI_IsEnabledDMAReq_TX + * @param SPIx SPI Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_SPI_IsEnabledDMAReq_TX(SPI_TypeDef *SPIx) +{ + return ((READ_BIT(SPIx->CR2, SPI_CR2_TXDMAEN) == (SPI_CR2_TXDMAEN)) ? 1UL : 0UL); +} + +/** + * @brief Set parity of Last DMA reception + * @rmtoll CR2 LDMARX LL_SPI_SetDMAParity_RX + * @param SPIx SPI Instance + * @param Parity This parameter can be one of the following values: + * @arg @ref LL_SPI_DMA_PARITY_ODD + * @arg @ref LL_SPI_DMA_PARITY_EVEN + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetDMAParity_RX(SPI_TypeDef *SPIx, uint32_t Parity) +{ + MODIFY_REG(SPIx->CR2, SPI_CR2_LDMARX, (Parity << SPI_CR2_LDMARX_Pos)); +} + +/** + * @brief Get parity configuration for Last DMA reception + * @rmtoll CR2 LDMARX LL_SPI_GetDMAParity_RX + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_DMA_PARITY_ODD + * @arg @ref LL_SPI_DMA_PARITY_EVEN + */ +__STATIC_INLINE uint32_t LL_SPI_GetDMAParity_RX(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR2, SPI_CR2_LDMARX) >> SPI_CR2_LDMARX_Pos); +} + +/** + * @brief Set parity of Last DMA transmission + * @rmtoll CR2 LDMATX LL_SPI_SetDMAParity_TX + * @param SPIx SPI Instance + * @param Parity This parameter can be one of the following values: + * @arg @ref LL_SPI_DMA_PARITY_ODD + * @arg @ref LL_SPI_DMA_PARITY_EVEN + * @retval None + */ +__STATIC_INLINE void LL_SPI_SetDMAParity_TX(SPI_TypeDef *SPIx, uint32_t Parity) +{ + MODIFY_REG(SPIx->CR2, SPI_CR2_LDMATX, (Parity << SPI_CR2_LDMATX_Pos)); +} + +/** + * @brief Get parity configuration for Last DMA transmission + * @rmtoll CR2 LDMATX LL_SPI_GetDMAParity_TX + * @param SPIx SPI Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_SPI_DMA_PARITY_ODD + * @arg @ref LL_SPI_DMA_PARITY_EVEN + */ +__STATIC_INLINE uint32_t LL_SPI_GetDMAParity_TX(SPI_TypeDef *SPIx) +{ + return (uint32_t)(READ_BIT(SPIx->CR2, SPI_CR2_LDMATX) >> SPI_CR2_LDMATX_Pos); +} + +/** + * @brief Get the data register address used for DMA transfer + * @rmtoll DR DR LL_SPI_DMA_GetRegAddr + * @param SPIx SPI Instance + * @retval Address of data register + */ +__STATIC_INLINE uint32_t LL_SPI_DMA_GetRegAddr(SPI_TypeDef *SPIx) +{ + return (uint32_t) & (SPIx->DR); +} + +/** + * @} + */ + +/** @defgroup SPI_LL_EF_DATA_Management DATA Management + * @{ + */ + +/** + * @brief Read 8-Bits in the data register + * @rmtoll DR DR LL_SPI_ReceiveData8 + * @param SPIx SPI Instance + * @retval RxData Value between Min_Data=0x00 and Max_Data=0xFF + */ +__STATIC_INLINE uint8_t LL_SPI_ReceiveData8(SPI_TypeDef *SPIx) +{ + return (uint8_t)(READ_REG(SPIx->DR)); +} + +/** + * @brief Read 16-Bits in the data register + * @rmtoll DR DR LL_SPI_ReceiveData16 + * @param SPIx SPI Instance + * @retval RxData Value between Min_Data=0x00 and Max_Data=0xFFFF + */ +__STATIC_INLINE uint16_t LL_SPI_ReceiveData16(SPI_TypeDef *SPIx) +{ + return (uint16_t)(READ_REG(SPIx->DR)); +} + +/** + * @brief Write 8-Bits in the data register + * @rmtoll DR DR LL_SPI_TransmitData8 + * @param SPIx SPI Instance + * @param TxData Value between Min_Data=0x00 and Max_Data=0xFF + * @retval None + */ +__STATIC_INLINE void LL_SPI_TransmitData8(SPI_TypeDef *SPIx, uint8_t TxData) +{ +#if defined (__GNUC__) + __IO uint8_t *spidr = ((__IO uint8_t *)&SPIx->DR); + *spidr = TxData; +#else + *((__IO uint8_t *)&SPIx->DR) = TxData; +#endif +} + +/** + * @brief Write 16-Bits in the data register + * @rmtoll DR DR LL_SPI_TransmitData16 + * @param SPIx SPI Instance + * @param TxData Value between Min_Data=0x00 and Max_Data=0xFFFF + * @retval None + */ +__STATIC_INLINE void LL_SPI_TransmitData16(SPI_TypeDef *SPIx, uint16_t TxData) +{ +#if defined (__GNUC__) + __IO uint16_t *spidr = ((__IO uint16_t *)&SPIx->DR); + *spidr = TxData; +#else + SPIx->DR = TxData; +#endif +} + +/** + * @} + */ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup SPI_LL_EF_Init Initialization and de-initialization functions + * @{ + */ + +ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx); +ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct); +void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct); + +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ +/** + * @} + */ + +/** + * @} + */ + +#endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32L4xx_LL_SPI_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/targets/stm32l432/src/ams.c b/targets/stm32l432/src/ams.c new file mode 100644 index 0000000..335758f --- /dev/null +++ b/targets/stm32l432/src/ams.c @@ -0,0 +1,366 @@ +#include + +#include "stm32l4xx_ll_spi.h" + +#include "ams.h" +#include "log.h" +#include "util.h" +#include "device.h" +#include "nfc.h" + +static void flush_rx() +{ + while(LL_SPI_IsActiveFlag_RXNE(SPI1) != 0) + { + LL_SPI_ReceiveData8(SPI1); + } +} +static void wait_for_tx() +{ + // while (LL_SPI_IsActiveFlag_BSY(SPI1) == 1) + // ; + while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) + ; +} +static void wait_for_rx() +{ + while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0) + ; +} + + +void ams_print_device(AMS_DEVICE * dev) +{ + printf1(TAG_NFC, "AMS_DEVICE:\r\n"); + printf1(TAG_NFC, " io_conf: %02x\r\n",dev->regs.io_conf); + printf1(TAG_NFC, " ic_conf0: %02x\r\n",dev->regs.ic_conf0); + printf1(TAG_NFC, " ic_conf1: %02x\r\n",dev->regs.ic_conf1); + printf1(TAG_NFC, " ic_conf2: %02x\r\n",dev->regs.ic_conf2); + printf1(TAG_NFC, " rfid_status: %02x\r\n",dev->regs.rfid_status); + printf1(TAG_NFC, " ic_status: %02x\r\n",dev->regs.ic_status); + printf1(TAG_NFC, " mask_int0: %02x\r\n",dev->regs.mask_int0); + printf1(TAG_NFC, " mask_int1: %02x\r\n",dev->regs.mask_int1); + printf1(TAG_NFC, " int0: %02x\r\n",dev->regs.int0); + printf1(TAG_NFC, " int1: %02x\r\n",dev->regs.int1); + printf1(TAG_NFC, " buffer_status2: %02x\r\n",dev->regs.buffer_status2); + printf1(TAG_NFC, " buffer_status1: %02x\r\n",dev->regs.buffer_status1); + printf1(TAG_NFC, " last_nfc_addr: %02x\r\n",dev->regs.last_nfc_addr); + printf1(TAG_NFC, " product_type: %02x\r\n",dev->regs.product_type); + printf1(TAG_NFC, " product_subtype:%02x\r\n",dev->regs.product_subtype); + printf1(TAG_NFC, " version_maj: %02x\r\n",dev->regs.version_maj); + printf1(TAG_NFC, " version_min: %02x\r\n",dev->regs.version_min); +} + +static uint8_t send_recv(uint8_t b) +{ + wait_for_tx(); + LL_SPI_TransmitData8(SPI1, b); + wait_for_rx(); + b = LL_SPI_ReceiveData8(SPI1); + return b; +} + + +void ams_write_reg(uint8_t addr, uint8_t tx) +{ + send_recv(0x00| addr); + send_recv(tx); + + UNSELECT(); + SELECT(); +} + + +uint8_t ams_read_reg(uint8_t addr) +{ + send_recv(0x20| (addr & 0x1f)); + uint8_t data = send_recv(0); + UNSELECT(); + SELECT(); + return data; +} + + +// data must be 14 bytes long +void read_reg_block(AMS_DEVICE * dev) +{ + int i; + uint8_t mode = 0x20 | (4 ); + flush_rx(); + + send_recv(mode); + for (i = 0x04; i < 0x0d; i++) + { + dev->buf[i] = send_recv(0); + } + + UNSELECT(); + SELECT(); +} + +void ams_read_buffer(uint8_t * data, int len) +{ + send_recv(0xa0); + while(len--) + { + *data++ = send_recv(0x00); + } + + UNSELECT(); + SELECT(); +} + +void ams_write_buffer(uint8_t * data, int len) +{ + send_recv(0x80); + while(len--) + { + send_recv(*data++); + } + + UNSELECT(); + SELECT(); +} + +// data must be 4 bytes +void ams_read_eeprom_block(uint8_t block, uint8_t * data) +{ + send_recv(0x7f); + send_recv(block << 1); + + data[0] = send_recv(0); + data[1] = send_recv(0); + data[2] = send_recv(0); + data[3] = send_recv(0); + + UNSELECT(); + SELECT(); +} + + +// data must be 4 bytes +void ams_write_eeprom_block(uint8_t block, uint8_t * data) +{ + send_recv(0x40); + send_recv(block << 1); + + send_recv(data[0]); + send_recv(data[1]); + send_recv(data[2]); + send_recv(data[3]); + + UNSELECT(); + SELECT(); +} + +void ams_write_command(uint8_t cmd) +{ + send_recv(0xc0 | cmd); + UNSELECT(); + SELECT(); +} + +const char * ams_get_state_string(uint8_t regval) +{ + if (regval & AMS_STATE_INVALID) + { + return "STATE_INVALID"; + } + switch (regval & AMS_STATE_MASK) + { + case AMS_STATE_OFF: + return "STATE_OFF"; + case AMS_STATE_SENSE: + return "STATE_SENSE"; + case AMS_STATE_RESOLUTION: + return "STATE_RESOLUTION"; + case AMS_STATE_RESOLUTION_L2: + return "STATE_RESOLUTION_L2"; + case AMS_STATE_SELECTED: + return "STATE_SELECTED"; + case AMS_STATE_SECTOR2: + return "STATE_SECTOR2"; + case AMS_STATE_SECTORX_2: + return "STATE_SECTORX_2"; + case AMS_STATE_SELECTEDX: + return "STATE_SELECTEDX"; + case AMS_STATE_SENSEX_L2: + return "STATE_SENSEX_L2"; + case AMS_STATE_SENSEX: + return "STATE_SENSEX"; + case AMS_STATE_SLEEP: + return "STATE_SLEEP"; + } + return "STATE_WRONG"; +} + +int ams_state_is_valid(uint8_t regval) +{ + if (regval & AMS_STATE_INVALID) + { + return 0; + } + switch (regval & AMS_STATE_MASK) + { + case AMS_STATE_OFF: + case AMS_STATE_SENSE: + case AMS_STATE_RESOLUTION: + case AMS_STATE_RESOLUTION_L2: + case AMS_STATE_SELECTED: + case AMS_STATE_SECTOR2: + case AMS_STATE_SECTORX_2: + case AMS_STATE_SELECTEDX: + case AMS_STATE_SENSEX_L2: + case AMS_STATE_SENSEX: + case AMS_STATE_SLEEP: + return 1; + } + return 0; +} + +void ams_print_int0(uint8_t int0) +{ +#if DEBUG_LEVEL + uint32_t tag = (TAG_NFC)|(TAG_NO_TAG); + printf1(TAG_NFC," "); + if (int0 & AMS_INT_XRF) + printf1(tag," XRF"); + if (int0 & AMS_INT_TXE) + printf1(tag," TXE"); + if (int0 & AMS_INT_RXE) + printf1(tag," RXE"); + if (int0 & AMS_INT_EER_RF) + printf1(tag," EER_RF"); + if (int0 & AMS_INT_EEW_RF) + printf1(tag," EEW_RF"); + if (int0 & AMS_INT_SLP) + printf1(tag," SLP"); + if (int0 & AMS_INT_WU_A) + printf1(tag," WU_A"); + if (int0 & AMS_INT_INIT) + printf1(tag," INIT"); + + printf1(tag,"\r\n"); +#endif +} + +void ams_print_int1(uint8_t int0) +{ +#if DEBUG_LEVEL + uint32_t tag = (TAG_NFC)|(TAG_NO_TAG); + printf1(TAG_NFC," "); + if (int0 & AMS_INT_ACC_ERR) + printf1(tag," ACC_ERR"); + if (int0 & AMS_INT_EEAC_ERR) + printf1(tag," EEAC_ERR"); + if (int0 & AMS_INT_IO_EEWR) + printf1(tag," IO_EEWR"); + if (int0 & AMS_INT_BF_ERR) + printf1(tag," BF_ERR"); + if (int0 & AMS_INT_CRC_ERR) + printf1(tag," CRC_ERR"); + if (int0 & AMS_INT_PAR_ERR) + printf1(tag," PAR_ERR"); + if (int0 & AMS_INT_FRM_ERR) + printf1(tag," FRM_ERR"); + if (int0 & AMS_INT_RXS) + printf1(tag," RXS"); + + printf1(tag,"\r\n"); +#endif +} + +void ams_init() +{ + LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN); + + LL_SPI_SetClockPolarity(SPI1,LL_SPI_POLARITY_LOW); + LL_SPI_SetClockPhase(SPI1,LL_SPI_PHASE_2EDGE); + LL_SPI_SetRxFIFOThreshold(SPI1,LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable(SPI1); + + // delay(10); + SELECT(); + delay(1); +} + +void ams_configure() +{ + // Should not be used during passive operation. + uint8_t block[4]; + + // check connection + uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE); + if (productType != 0x14) + { + printf1(TAG_ERR, "Have wrong product type [0x%02x]. AMS3956 connection error.\n", productType); + } + + printf1(TAG_NFC,"AMS3956 product type 0x%02x.\n", productType); + + ams_read_eeprom_block(AMS_CONFIG_UID_ADDR, block); + printf1(TAG_NFC,"UID: 3F 14 02 - "); dump_hex1(TAG_NFC,block,4); + + ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block); + printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4); + + uint8_t sense1 = 0x44; + uint8_t sense2 = 0x00; + uint8_t selr = 0x20; // SAK + + if(block[0] != sense1 || block[1] != sense2 || block[2] != selr) + { + printf1(TAG_NFC,"Writing config block 0\r\n"); + block[0] = sense1; + block[1] = sense2; + block[2] = selr; + block[3] = 0x00; + + ams_write_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block); + UNSELECT(); + delay(10); + SELECT(); + delay(10); + + ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block); + printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4); + } + + ams_read_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block); + printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4); + + uint8_t ic_cfg1 = AMS_CFG1_OUTPUT_RESISTANCE_100 | AMS_CFG1_VOLTAGE_LEVEL_2V0; + uint8_t ic_cfg2 = AMS_CFG2_TUN_MOD; + + if (block[0] != ic_cfg1 || block[1] != ic_cfg2) + { + + printf1(TAG_NFC,"Writing config block 1\r\n"); + + ams_write_reg(AMS_REG_IC_CONF1,ic_cfg1); + ams_write_reg(AMS_REG_IC_CONF2,ic_cfg2); + + // set IC_CFG1 + block[0] = ic_cfg1; + + // set IC_CFG2 + block[1] = ic_cfg2; + + // mask interrupt bits + block[2] = 0x80; + block[3] = 0; + + ams_write_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block); + + UNSELECT(); + delay(10); + SELECT(); + delay(10); + + ams_read_eeprom_block(0x7F, block); + printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4); + } + + +} diff --git a/targets/stm32l432/src/ams.h b/targets/stm32l432/src/ams.h new file mode 100644 index 0000000..ef701bf --- /dev/null +++ b/targets/stm32l432/src/ams.h @@ -0,0 +1,162 @@ +// AS3956 interface +// https://ams.com/as3956 +// https://ams.com/documents/20143/36005/AS3956_DS000546_7-00.pdf + +#ifndef _AMS_H_ +#define _AMS_H_ + +#include +#include +#include "stm32l4xx_ll_gpio.h" + + +typedef union +{ + uint8_t buf[0x20]; + struct { + uint8_t io_conf; // 0x00 + uint8_t ic_conf0; // 0x01 + uint8_t ic_conf1; // 0x02 + uint8_t ic_conf2; // 0x03 + uint8_t rfid_status; // 0x04 + uint8_t ic_status; // 0x05 + uint8_t _nc0[2]; // 0x06 - 0x07 + uint8_t mask_int0; // 0x08 + uint8_t mask_int1; // 0x09 + uint8_t int0; // 0x0a + uint8_t int1; // 0x0b + uint8_t buffer_status2; // 0x0c + uint8_t buffer_status1; // 0x0d + uint8_t last_nfc_addr; // 0x0e + uint8_t _nc1[0x1b - 0x0f + 1]; // 0x0f - 0x1b + uint8_t product_type; // 0x1c + uint8_t product_subtype; // 0x1d + uint8_t version_maj; // 0x1e + uint8_t version_min; // 0x1f + } regs; +} __attribute__((packed)) AMS_DEVICE; + +#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN) +#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN) + +void ams_init(); +void ams_configure(); + +void ams_read_buffer(uint8_t * data, int len); +void ams_write_buffer(uint8_t * data, int len); + +void ams_write_command(uint8_t cmd); + +void read_reg_block(AMS_DEVICE * dev); + +uint8_t ams_read_reg(uint8_t addr); + +void ams_write_reg(uint8_t addr, uint8_t tx); + +const char * ams_get_state_string(uint8_t regval); +int ams_state_is_valid(uint8_t regval); + + +#define AMS_REG_IO_CONF 0x00 +#define AMS_REG_IC_CONF0 0x01 +#define AMS_REG_IC_CONF1 0x02 +#define AMS_REG_IC_CONF2 0x03 + #define AMS_RFCFG_EN 0x80 + #define AMS_TUN_MOD 0x40 +#define AMS_REG_RFID_STATUS 0x04 + #define AMS_HF_PON 0x80 + #define AMS_STATE_MASK 0x78 + #define AMS_STATE_INVALID 0x04 + #define AMS_STATE_OFF (0 << 3) + #define AMS_STATE_SENSE (1 << 3) + #define AMS_STATE_RESOLUTION (3 << 3) + #define AMS_STATE_RESOLUTION_L2 (2 << 3) + #define AMS_STATE_SELECTED (6 << 3) + #define AMS_STATE_SECTOR2 (7 << 3) + #define AMS_STATE_SECTORX_2 (0xf << 3) + #define AMS_STATE_SELECTEDX (0xe << 3) + #define AMS_STATE_SENSEX_L2 (0xa << 3) + #define AMS_STATE_SENSEX (0xb << 3) + #define AMS_STATE_SLEEP (0x9 << 3) +// ... // +#define AMS_REG_MASK_INT0 0x08 + #define AMS_MASK0_PU (1<<7) // power up + #define AMS_MASK0_WU_A (1<<6) // selected INT + #define AMS_MASK0_SLP (1<<5) + #define AMS_MASK0_EEW_RF (1<<4) + #define AMS_MASK0_EER_RF (1<<3) + #define AMS_MASK0_RXE (1<<2) + #define AMS_MASK0_TXE (1<<1) + #define AMS_MASK0_XRF (1<<0) +#define AMS_REG_MASK_INT1 0x09 +#define AMS_REG_INT0 0x0a + #define AMS_INT_XRF (1<<0) + #define AMS_INT_TXE (1<<1) + #define AMS_INT_RXE (1<<2) + #define AMS_INT_EER_RF (1<<3) + #define AMS_INT_EEW_RF (1<<4) + #define AMS_INT_SLP (1<<5) + #define AMS_INT_WU_A (1<<6) + #define AMS_INT_INIT (1<<7) +#define AMS_REG_INT1 0x0b + #define AMS_INT_ACC_ERR (1<<0) + #define AMS_INT_EEAC_ERR (1<<1) + #define AMS_INT_IO_EEWR (1<<2) + #define AMS_INT_BF_ERR (1<<3) + #define AMS_INT_CRC_ERR (1<<4) + #define AMS_INT_PAR_ERR (1<<5) + #define AMS_INT_FRM_ERR (1<<6) + #define AMS_INT_RXS (1<<7) +#define AMS_REG_BUF2 0x0c + #define AMS_BUF_LEN_MASK 0x1f + #define AMS_BUF_INVALID 0x80 +#define AMS_REG_BUF1 0x0d +// ... // +#define AMS_REG_PRODUCT_TYPE 0x1c +#define AMS_REG_PRODUCT_SUBTYPE 0x1d +#define AMS_REG_VERSION_MAJOR 0x1e +#define AMS_REG_VERSION_MINOR 0x1f + +#define AMS_CONFIG_UID_ADDR 0x00 +#define AMS_CONFIG_BLOCK0_ADDR 0x7e +#define AMS_CONFIG_BLOCK1_ADDR 0x7f + +#define AMS_CFG1_VOLTAGE_LEVEL_1V9 (0x00<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V0 (0x01<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V1 (0x02<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V2 (0x03<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V3 (0x04<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V4 (0x05<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V5 (0x06<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V6 (0x07<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V7 (0x08<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V8 (0x09<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_2V9 (0x0a<<2) +#define AMS_CFG1_VOLTAGE_LEVEL_3V0 (0x0b<<2) + +#define AMS_CFG1_OUTPUT_RESISTANCE_ZZ 0x00 +#define AMS_CFG1_OUTPUT_RESISTANCE_100 0x01 +#define AMS_CFG1_OUTPUT_RESISTANCE_50 0x02 +#define AMS_CFG1_OUTPUT_RESISTANCE_25 0x03 + +#define AMS_CFG2_RFCFG_EN (1<<7) +#define AMS_CFG2_TUN_MOD (1<<6) + +#define AMS_CMD_DEFAULT 0x02 +#define AMS_CMD_CLEAR_BUFFER 0x04 +#define AMS_CMD_RESTART_TRANSCEIVER 0x06 +#define AMS_CMD_DIS_EN_TRANSCEIVER 0x07 +#define AMS_CMD_TRANSMIT_BUFFER 0x08 +#define AMS_CMD_TRANSMIT_ACK 0x09 +#define AMS_CMD_TRANSMIT_NACK0 0x0A +#define AMS_CMD_TRANSMIT_NACK1 0x0B +#define AMS_CMD_TRANSMIT_NACK4 0x0D +#define AMS_CMD_TRANSMIT_NACK5 0x0C +#define AMS_CMD_SLEEP 0x10 +#define AMS_CMD_SENSE 0x11 +#define AMS_CMD_SENSE_SLEEP 0x12 + + + + +#endif diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h index c05a9b3..8570d24 100644 --- a/targets/stm32l432/src/app.h +++ b/targets/stm32l432/src/app.h @@ -30,6 +30,7 @@ // #define DISABLE_CTAPHID_WINK // #define DISABLE_CTAPHID_CBOR +#define ENABLE_SERIAL_PRINTING #if defined(SOLO_HACKER) #define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION @@ -38,7 +39,7 @@ #endif void printing_init(); -void hw_init(void); +void hw_init(int lf); //#define TEST //#define TEST_POWER @@ -63,6 +64,12 @@ void hw_init(void); #define SOLO_BUTTON_PORT GPIOA #define SOLO_BUTTON_PIN LL_GPIO_PIN_0 +#define SOLO_AMS_CS_PORT GPIOB +#define SOLO_AMS_CS_PIN LL_GPIO_PIN_0 + +#define SOLO_AMS_IRQ_PORT GPIOC +#define SOLO_AMS_IRQ_PIN LL_GPIO_PIN_15 + #define SKIP_BUTTON_CHECK_WITH_DELAY 0 #define SKIP_BUTTON_CHECK_FAST 0 diff --git a/targets/stm32l432/src/device.c b/targets/stm32l432/src/device.c index 59b19d6..d65b7f8 100644 --- a/targets/stm32l432/src/device.c +++ b/targets/stm32l432/src/device.c @@ -10,6 +10,7 @@ #include "stm32l4xx_ll_gpio.h" #include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_usart.h" +#include "stm32l4xx_ll_pwr.h" #include "usbd_hid.h" #include APP_CONFIG @@ -26,6 +27,11 @@ #include "memory_layout.h" #include "stm32l4xx_ll_iwdg.h" #include "usbd_cdc_if.h" +#include "nfc.h" +#include "init.h" + +#define LOW_FREQUENCY 1 +#define HIGH_FREQUENCY 0 void wait_for_usb_tether(); @@ -34,6 +40,8 @@ uint32_t __90_ms = 0; uint32_t __device_status = 0; uint32_t __last_update = 0; extern PCD_HandleTypeDef hpcd; +static bool haveNFC = 0; +static bool isLowFreq = 0; #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) @@ -50,6 +58,13 @@ void TIM6_DAC_IRQHandler() ctaphid_update_status(__device_status); } } +#ifndef IS_BOOTLOADER + // NFC sending WTX if needs + if (device_is_nfc()) + { + WTX_timer_exec(); + } +#endif } // Global USB interrupt handler @@ -91,32 +106,45 @@ void device_reboot() { NVIC_SystemReset(); } + void device_init() { - hw_init(); - LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT); - LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP); -#ifndef IS_BOOTLOADER + hw_init(LOW_FREQUENCY); + isLowFreq = 1; + + haveNFC = nfc_init(); + + if (haveNFC) + { + printf1(TAG_NFC, "Have NFC\r\n"); + } + else + { + printf1(TAG_NFC, "Have NO NFC\r\n"); + hw_init(HIGH_FREQUENCY); + + isLowFreq = 0; + } + + usbhid_init(); + + ctaphid_init(); + + ctap_init( !haveNFC ); + #if BOOT_TO_DFU flash_option_bytes_init(1); #else flash_option_bytes_init(0); -#endif #endif - printf1(TAG_GEN,"hello solo\r\n"); + } -void usb_init(void); -void usbhid_init() +bool device_is_nfc() { - usb_init(); - -#if DEBUG_LEVEL>1 - wait_for_usb_tether(); -#endif - + return haveNFC; } void wait_for_usb_tether() @@ -130,6 +158,26 @@ void wait_for_usb_tether() ; } +void usbhid_init() +{ + if (!isLowFreq) + { + init_usb(); + +#if DEBUG_LEVEL>1 + wait_for_usb_tether(); +#endif + } + else + { + + + + } +} + + + int usbhid_recv(uint8_t * msg) { if (fifo_hidmsg_size()) @@ -366,6 +414,7 @@ uint32_t ctap_atomic_count(int sel) } + void device_manage() { #if NON_BLOCK_PRINTING @@ -386,6 +435,10 @@ void device_manage() } } #endif +#ifndef IS_BOOTLOADER + // if(device_is_nfc()) + nfc_loop(); +#endif } static int handle_packets() diff --git a/targets/stm32l432/src/init.c b/targets/stm32l432/src/init.c index b5bfedb..3e704ea 100644 --- a/targets/stm32l432/src/init.c +++ b/targets/stm32l432/src/init.c @@ -18,6 +18,7 @@ #include "stm32l4xx_ll_bus.h" #include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_rng.h" +#include "stm32l4xx_ll_spi.h" #include "stm32l4xx_ll_usb.h" #include "stm32l4xx_hal_pcd.h" #include "stm32l4xx_hal.h" @@ -29,57 +30,86 @@ #include "usbd_composite.h" #include "usbd_cdc_if.h" #include "device.h" +#include "init.h" #include APP_CONFIG -/* USER CODE BEGIN Includes */ +// KHz +#define MAX_CLOCK_RATE 24000 -/* USER CODE END Includes */ +#define SET_CLOCK_RATE2() SystemClock_Config() -/* Private variables ---------------------------------------------------------*/ +#if MAX_CLOCK_RATE == 48000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF32() + #define SET_CLOCK_RATE1() SystemClock_Config_LF48() +#elif MAX_CLOCK_RATE == 32000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF24() + #define SET_CLOCK_RATE1() SystemClock_Config_LF32() +#elif MAX_CLOCK_RATE == 28000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF24() + #define SET_CLOCK_RATE1() SystemClock_Config_LF28() +#elif MAX_CLOCK_RATE == 24000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF16() + #define SET_CLOCK_RATE1() SystemClock_Config_LF24() +#elif MAX_CLOCK_RATE == 20000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF16() + #define SET_CLOCK_RATE1() SystemClock_Config_LF20() +#elif MAX_CLOCK_RATE == 16000 + #define SET_CLOCK_RATE0() SystemClock_Config_LF8() + #define SET_CLOCK_RATE1() SystemClock_Config_LF16() +#else +#error "Invalid clock rate selected" +#endif USBD_HandleTypeDef Solo_USBD_Device; -/* Private function prototypes -----------------------------------------------*/ static void LL_Init(void); -void SystemClock_Config(void); -static void MX_GPIO_Init(void); -#if DEBUG_LEVEL > 0 -static void MX_USART1_UART_Init(void); -#endif -static void MX_TIM2_Init(void); -static void MX_TIM6_Init(void); -static void MX_RNG_Init(void); #define Error_Handler() _Error_Handler(__FILE__,__LINE__) void _Error_Handler(char *file, int line); +void SystemClock_Config(void); +void SystemClock_Config_LF16(void); +void SystemClock_Config_LF20(void); +void SystemClock_Config_LF24(void); +void SystemClock_Config_LF28(void); +void SystemClock_Config_LF48(void); -void hw_init(void) +void hw_init(int lowfreq) { #ifdef IS_BOOTLOADER SCB->VTOR = FLASH_BASE; #else #endif LL_Init(); + init_gpio(); - SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + if (lowfreq) + { + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); // Under voltage + device_set_clock_rate(DEVICE_LOW_POWER_IDLE); + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); + } + else + { + SystemClock_Config(); + } - SystemClock_Config(); // TODO bootloader should not change clk freq. - MX_GPIO_Init(); - MX_TIM2_Init(); // PWM for LEDs - MX_TIM6_Init(); // ~1 ms timer + if (!lowfreq) + { + init_pwm(); + } + + init_millisecond_timer(lowfreq); #if DEBUG_LEVEL > 0 - MX_USART1_UART_Init();// debug uart + init_debug_uart(); #endif - MX_RNG_Init(); + init_rng(); + init_spi(); - TIM6->SR = 0; - __enable_irq(); - NVIC_EnableIRQ(TIM6_IRQn); } static void LL_Init(void) @@ -107,25 +137,443 @@ static void LL_Init(void) } +void device_set_clock_rate(DEVICE_CLOCK_RATE param) +{ + switch(param) + { + case DEVICE_LOW_POWER_IDLE: + SET_CLOCK_RATE0(); + break; + case DEVICE_LOW_POWER_FAST: + SET_CLOCK_RATE1(); + break; + case DEVICE_FAST: + SET_CLOCK_RATE2(); + break; + } +} + /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); - LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); + LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); - if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_HSI48_Enable(); + + /* Wait till HSI48 is ready */ + while(LL_RCC_HSI48_IsReady() != 1) + { + + } + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16); + + LL_Init1msTick(48000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(48000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_HSI48); + + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); + + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_CRS); + + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_CRS); + + LL_CRS_SetSyncDivider(LL_CRS_SYNC_DIV_1); + + LL_CRS_SetSyncPolarity(LL_CRS_SYNC_POLARITY_RISING); + + LL_CRS_SetSyncSignalSource(LL_CRS_SYNC_SOURCE_USB); + + LL_CRS_SetReloadCounter(__LL_CRS_CALC_CALCULATE_RELOADVALUE(48000000,1000)); + + LL_CRS_SetFreqErrorLimit(34); + + LL_CRS_SetHSI48SmoothTrimming(32); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); +} + +void SystemClock_Config_LF4(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + LL_Init1msTick(4000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(4000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + + + +} + +// 8MHz +void SystemClock_Config_LF8(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + // while(LL_RCC_LSI_IsReady() != 1) + // { + // + // } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + // while(LL_RCC_MSI_IsReady() != 1) + // { + // + // } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_7); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + // while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + // { + // + // } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + LL_Init1msTick(8000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(8000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + +} + +// 16MHz +void SystemClock_Config_LF16(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_8); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + LL_Init1msTick(16000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(16000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + +} + + + +// 24 MHz +void SystemClock_Config_LF24(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_1); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_9); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8); + + LL_Init1msTick(24000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(24000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + +} + +// 32 MHz +void SystemClock_Config_LF32(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_1); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_10); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16); + + LL_Init1msTick(32000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(32000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + +} + +// 28 MHz +void SystemClock_Config_LF28(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + LL_FLASH_SetLatency(LL_FLASH_LATENCY_1); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1) { Error_Handler(); } LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); - LL_RCC_HSI48_Enable(); + LL_RCC_HSI_Enable(); - /* Wait till HSI48 is ready */ - while(LL_RCC_HSI48_IsReady() != 1) + /* Wait till HSI is ready */ + while(LL_RCC_HSI_IsReady() != 1) + { + + } + LL_RCC_HSI_SetCalibTrimming(16); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) { } @@ -138,14 +586,25 @@ void SystemClock_Config(void) } LL_RCC_MSI_EnableRangeSelection(); - LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11); + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6); LL_RCC_MSI_SetCalibTrimming(0); - LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_2, 28, LL_RCC_PLLR_DIV_8); + + LL_RCC_PLL_EnableDomain_SYS(); + + LL_RCC_PLL_Enable(); + + /* Wait till PLL is ready */ + while(LL_RCC_PLL_IsReady() != 1) + { + + } + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); /* Wait till System clock is ready */ - while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { } @@ -153,41 +612,92 @@ void SystemClock_Config(void) LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); - LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8); - LL_Init1msTick(48000000); + LL_Init1msTick(28000000); LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); - LL_SetSystemCoreClock(48000000); + LL_SetSystemCoreClock(28000000); LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); - LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_HSI48); - - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); - - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_CRS); - - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_CRS); - - LL_CRS_SetSyncDivider(LL_CRS_SYNC_DIV_1); - - LL_CRS_SetSyncPolarity(LL_CRS_SYNC_POLARITY_RISING); - - LL_CRS_SetSyncSignalSource(LL_CRS_SYNC_SOURCE_USB); - - LL_CRS_SetReloadCounter(__LL_CRS_CALC_CALCULATE_RELOADVALUE(48000000,1000)); - - LL_CRS_SetFreqErrorLimit(34); - - LL_CRS_SetHSI48SmoothTrimming(32); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); /* SysTick_IRQn interrupt configuration */ NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); } -void usb_init() +// 48 MHz +void SystemClock_Config_LF48(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); + + + LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); + + if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) + { + Error_Handler(); + } + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_LSI_Enable(); + + /* Wait till LSI is ready */ + while(LL_RCC_LSI_IsReady() != 1) + { + + } + LL_RCC_MSI_Enable(); + + /* Wait till MSI is ready */ + while(LL_RCC_MSI_IsReady() != 1) + { + + } + LL_RCC_MSI_EnableRangeSelection(); + + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11); + + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI); + + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) + { + + } + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16); + + LL_Init1msTick(48000000); + + LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); + + LL_SetSystemCoreClock(48000000); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI); + + /* SysTick_IRQn interrupt configuration */ + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + + +} + +// 20 MHz +void SystemClock_Config_LF20(void) +{ + SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); +} + +void init_usb() { // enable USB power SET_BIT(PWR->CR2, PWR_CR2_USV); @@ -217,81 +727,78 @@ void usb_init() USBD_Start(&Solo_USBD_Device); } -/* TIM2 init function */ -static void MX_TIM2_Init(void) +void init_pwm(void) { - LL_TIM_InitTypeDef TIM_InitStruct; - LL_TIM_OC_InitTypeDef TIM_OC_InitStruct; + LL_TIM_InitTypeDef TIM_InitStruct; + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct; - LL_GPIO_InitTypeDef GPIO_InitStruct; + LL_GPIO_InitTypeDef GPIO_InitStruct; - /* Peripheral clock enable */ - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); + /* Peripheral clock enable */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); - TIM2->SR = 0 ; + TIM2->SR = 0 ; - TIM_InitStruct.Prescaler = 0; - TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; - TIM_InitStruct.Autoreload = 1000; - TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - LL_TIM_Init(TIM2, &TIM_InitStruct); + TIM_InitStruct.Prescaler = 0; + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = 1000; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; + LL_TIM_Init(TIM2, &TIM_InitStruct); - LL_TIM_EnableARRPreload(TIM2); + LL_TIM_EnableARRPreload(TIM2); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; - TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; - TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; - TIM_OC_InitStruct.CompareValue = 1000; - TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.CompareValue = 1000; + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); - LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); - TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; - TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct); + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct); - LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH3); + LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH3); - TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; - TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH4, &TIM_OC_InitStruct); + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH4, &TIM_OC_InitStruct); - LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH4); + LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH4); - LL_TIM_SetOCRefClearInputSource(TIM2, LL_TIM_OCREF_CLR_INT_NC); + LL_TIM_SetOCRefClearInputSource(TIM2, LL_TIM_OCREF_CLR_INT_NC); - LL_TIM_DisableExternalClock(TIM2); + LL_TIM_DisableExternalClock(TIM2); - LL_TIM_ConfigETR(TIM2, LL_TIM_ETR_POLARITY_NONINVERTED, LL_TIM_ETR_PRESCALER_DIV1, LL_TIM_ETR_FILTER_FDIV1); + LL_TIM_ConfigETR(TIM2, LL_TIM_ETR_POLARITY_NONINVERTED, LL_TIM_ETR_PRESCALER_DIV1, LL_TIM_ETR_FILTER_FDIV1); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); + LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_DisableMasterSlaveMode(TIM2); + LL_TIM_DisableMasterSlaveMode(TIM2); - /**TIM2 GPIO Configuration - PA1 ------> TIM2_CH2 - PA2 ------> TIM2_CH3 - PA3 ------> TIM2_CH4 - */ - GPIO_InitStruct.Pin = LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_3; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - GPIO_InitStruct.Alternate = LL_GPIO_AF_1; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + /**TIM2 GPIO Configuration + PA1 ------> TIM2_CH2 + PA2 ------> TIM2_CH3 + PA3 ------> TIM2_CH4 + */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_3; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_1; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); - LL_TIM_EnableCounter(TIM2); + LL_TIM_EnableCounter(TIM2); } -#if DEBUG_LEVEL > 0 -/* USART1 init function */ -static void MX_USART1_UART_Init(void) +void init_debug_uart(void) { LL_USART_InitTypeDef USART_InitStruct; @@ -301,6 +808,8 @@ static void MX_USART1_UART_Init(void) /* Peripheral clock enable */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); + + LL_USART_DeInit(USART1); /**USART1 GPIO Configuration PB6 ------> USART1_TX PB7 ------> USART1_RX @@ -327,80 +836,74 @@ static void MX_USART1_UART_Init(void) LL_USART_Enable(USART1); } -#endif -/** Pinout Configuration -*/ -static void MX_GPIO_Init(void) +void init_gpio(void) { /* GPIO Ports Clock Enable */ LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + + + LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT); + LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP); + +#ifdef SOLO_AMS_IRQ_PORT +// SAVE POWER + // LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); + // /**/ + // LL_GPIO_InitTypeDef GPIO_InitStruct; + // GPIO_InitStruct.Pin = SOLO_AMS_IRQ_PIN; + // GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT; + // GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + // LL_GPIO_Init(SOLO_AMS_IRQ_PORT, &GPIO_InitStruct); + // + // + // LL_GPIO_SetPinMode(SOLO_AMS_IRQ_PORT,SOLO_AMS_IRQ_PIN,LL_GPIO_MODE_INPUT); + // LL_GPIO_SetPinPull(SOLO_AMS_IRQ_PORT,SOLO_AMS_IRQ_PIN,LL_GPIO_PULL_UP); +#endif + } - -/* TIM6 init function */ -static void MX_TIM6_Init(void) +void init_millisecond_timer(int lf) { - LL_TIM_InitTypeDef TIM_InitStruct; + LL_TIM_InitTypeDef TIM_InitStruct; - /* Peripheral clock enable */ - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6); + /* Peripheral clock enable */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6); - // 48 MHz sys clock --> 6 MHz timer clock - // 48 MHz / 48000 == 1000 Hz - TIM_InitStruct.Prescaler = 48000; - TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; - TIM_InitStruct.Autoreload = 90; - LL_TIM_Init(TIM6, &TIM_InitStruct); + // 48 MHz sys clock --> 6 MHz timer clock + // 48 MHz / 48000 == 1000 Hz + if (!lf) + TIM_InitStruct.Prescaler = 48000; + else + TIM_InitStruct.Prescaler = MAX_CLOCK_RATE; - LL_TIM_DisableARRPreload(TIM6); + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = 90; + LL_TIM_Init(TIM6, &TIM_InitStruct); - LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_RESET); + LL_TIM_DisableARRPreload(TIM6); - LL_TIM_DisableMasterSlaveMode(TIM6); + LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_RESET); - // enable interrupt - TIM6->DIER |= 1; + LL_TIM_DisableMasterSlaveMode(TIM6); - // Start immediately - LL_TIM_EnableCounter(TIM6); + // enable interrupt + TIM6->DIER |= 1; + + // Start immediately + LL_TIM_EnableCounter(TIM6); + + TIM6->SR = 0; + __enable_irq(); + NVIC_EnableIRQ(TIM6_IRQn); } -/* TIM7 init function */ -// static void MX_TIM7_Init(void) -// { -// -// LL_TIM_InitTypeDef TIM_InitStruct; -// -// /* Peripheral clock enable */ -// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7); -// -// // 48 MHz sys clock --> 6 MHz timer clock -// // 6 MHz / 6000 == 1000 Hz -// TIM_InitStruct.Prescaler = 48000; -// TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; -// TIM_InitStruct.Autoreload = 0xffff; -// LL_TIM_Init(TIM6, &TIM_InitStruct); -// -// LL_TIM_DisableARRPreload(TIM7); -// -// LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_RESET); -// -// LL_TIM_DisableMasterSlaveMode(TIM7); -// -// // enable interrupt -// TIM7->DIER |= 1; -// -// // Start immediately -// LL_TIM_EnableCounter(TIM7); -// } -/* RNG init function */ -static void MX_RNG_Init(void) +void init_rng(void) { /* Peripheral clock enable */ @@ -409,3 +912,45 @@ static void MX_RNG_Init(void) LL_RNG_Enable(RNG); } + +/* SPI1 init function */ +void init_spi(void) +{ + + LL_SPI_InitTypeDef SPI_InitStruct; + + LL_GPIO_InitTypeDef GPIO_InitStruct; + + /* Peripheral clock enable */ + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); + + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_6|LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_5; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* SPI1 parameter configuration*/ + SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; + SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; + SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; + SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW; + SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE; + SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; + SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; + SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; + SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; + SPI_InitStruct.CRCPoly = 7; + LL_SPI_Init(SPI1, &SPI_InitStruct); + + LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA); + + +} diff --git a/targets/stm32l432/src/init.h b/targets/stm32l432/src/init.h new file mode 100644 index 0000000..729e898 --- /dev/null +++ b/targets/stm32l432/src/init.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 SoloKeys, Inc. + * + * This file is part of Solo. + * + * Solo 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. + * + * Solo 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 Solo. If not, see + * + * This code is available under licenses for commercial use. + * Please contact SoloKeys for more information. + */ +#ifndef _INIT_H_ +#define _INIT_H_ + +void init_usb(); +void init_gpio(void); +void init_debug_uart(void); +void init_pwm(void); +void init_millisecond_timer(int lf); +void init_rng(void); +void init_spi(void); + + +#endif diff --git a/targets/stm32l432/src/nfc.c b/targets/stm32l432/src/nfc.c new file mode 100644 index 0000000..ab0ddf3 --- /dev/null +++ b/targets/stm32l432/src/nfc.c @@ -0,0 +1,799 @@ +#include + +#include "stm32l4xx.h" + +#include "nfc.h" +#include "ams.h" +#include "log.h" +#include "util.h" +#include "device.h" +#include "u2f.h" +#include "crypto.h" + +#include "ctap_errors.h" + +#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN)) + +// Capability container +const CAPABILITY_CONTAINER NFC_CC = { + .cclen_hi = 0x00, .cclen_lo = 0x0f, + .version = 0x20, + .MLe_hi = 0x00, .MLe_lo = 0x7f, + .MLc_hi = 0x00, .MLc_lo = 0x7f, + .tlv = { 0x04,0x06, + 0xe1,0x04, + 0x00,0x7f, + 0x00,0x00 } +}; + +// 13 chars +uint8_t NDEF_SAMPLE[] = "\x00\x14\xd1\x01\x0eU\x04solokeys.com/"; + +// Poor way to get some info while in passive operation +#include +void nprintf(const char *format, ...) +{ + memmove((char*)NDEF_SAMPLE + sizeof(NDEF_SAMPLE) - 1 - 13," ", 13); + va_list args; + va_start (args, format); + vsnprintf ((char*)NDEF_SAMPLE + sizeof(NDEF_SAMPLE) - 1 - 13, 13, format, args); + va_end (args); +} + +static struct +{ + uint8_t max_frame_size; + uint8_t cid; + uint8_t block_num; + uint8_t selected_applet; +} NFC_STATE; + +void nfc_state_init() +{ + memset(&NFC_STATE,0,sizeof(NFC_STATE)); + NFC_STATE.max_frame_size = 32; + NFC_STATE.block_num = 1; +} + +bool nfc_init() +{ + uint32_t t1; + nfc_state_init(); + ams_init(); + + // Detect if we are powered by NFC field by listening for a message for + // first 25 ms. + t1 = millis(); + while ((millis() - t1) < 25) + { + if (nfc_loop() > 0) + return 1; + } + + // Under USB power. Configure AMS chip. + ams_configure(); + + return 0; +} + +void process_int0(uint8_t int0) +{ + +} + +bool ams_wait_for_tx(uint32_t timeout_ms) +{ + uint32_t tstart = millis(); + while (tstart + timeout_ms > millis()) + { + uint8_t int0 = ams_read_reg(AMS_REG_INT0); + if (int0) process_int0(int0); + if (int0 & AMS_INT_TXE) + return true; + + delay(1); + } + + return false; +} + +bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, int *dlen) +{ + uint8_t buf[32]; + *dlen = 0; + + uint32_t tstart = millis(); + while (tstart + timeout_ms > millis()) + { + uint8_t int0 = ams_read_reg(AMS_REG_INT0); + uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2); + + if (buffer_status2 && (int0 & AMS_INT_RXE)) + { + if (buffer_status2 & AMS_BUF_INVALID) + { + printf1(TAG_NFC,"Buffer being updated!\r\n"); + } + else + { + uint8_t len = buffer_status2 & AMS_BUF_LEN_MASK; + ams_read_buffer(buf, len); + printf1(TAG_NFC_APDU, ">> "); + dump_hex1(TAG_NFC_APDU, buf, len); + + *dlen = MIN(32, MIN(maxlen, len)); + memcpy(data, buf, *dlen); + + return true; + } + } + + delay(1); + } + + return false; +} + +void nfc_write_frame(uint8_t * data, uint8_t len) +{ + if (len > 32) + { + len = 32; + } + ams_write_command(AMS_CMD_CLEAR_BUFFER); + ams_write_buffer(data,len); + ams_write_command(AMS_CMD_TRANSMIT_BUFFER); + + printf1(TAG_NFC_APDU, "<< "); + dump_hex1(TAG_NFC_APDU, data, len); +} + +bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t resp) +{ + uint8_t res[32]; + + if (len > 32 - 3) + return false; + + res[0] = NFC_CMD_IBLOCK | (req0 & 3); + + if (len && data) + memcpy(&res[1], data, len); + + res[len + 1] = resp >> 8; + res[len + 2] = resp & 0xff; + nfc_write_frame(res, 3 + len); + + return true; +} + +bool nfc_write_response(uint8_t req0, uint16_t resp) +{ + return nfc_write_response_ex(req0, NULL, 0, resp); +} + +void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len) +{ + uint8_t res[32 + 2]; + int sendlen = 0; + uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 3); + + if (len <= 31) + { + uint8_t res[32] = {0}; + res[0] = iBlock; + if (len && data) + memcpy(&res[1], data, len); + nfc_write_frame(res, len + 1); + } else { + do { + // transmit I block + int vlen = MIN(31, len - sendlen); + res[0] = iBlock; + memcpy(&res[1], &data[sendlen], vlen); + + // if not a last block + if (vlen + sendlen < len) + { + res[0] |= 0x10; + } + + // send data + nfc_write_frame(res, vlen + 1); + sendlen += vlen; + + // wait for transmit (32 bytes aprox 2,5ms) + // if (!ams_wait_for_tx(10)) + // { + // printf1(TAG_NFC, "TX timeout. slen: %d \r\n", sendlen); + // break; + // } + + // if needs to receive R block (not a last block) + if (res[0] & 0x10) + { + uint8_t recbuf[32] = {0}; + int reclen; + if (!ams_receive_with_timeout(100, recbuf, sizeof(recbuf), &reclen)) + { + printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len); + break; + } + + if (reclen != 1) + { + printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen,sendlen,len); + dump_hex1(TAG_NFC, recbuf, reclen); + break; + } + + if (((recbuf[0] & 0x01) == (res[0] & 1)) && ((recbuf[0] & 0xf6) == 0xa2)) + { + printf1(TAG_NFC, "R block error. txdata: %02x rxdata: %02x \r\n", res[0], recbuf[0]); + break; + } + } + + iBlock ^= 0x01; + } while (sendlen < len); + } +} + +// WTX on/off: +// sends/receives WTX frame to reader every `WTX_time` time in ms +// works via timer interrupts +// WTX: f2 01 91 40 === f2(S-block + WTX, frame without CID) 01(from iso - multiply WTX from ATS by 1) <2b crc16> +static bool WTX_sent; +static bool WTX_fail; +static uint32_t WTX_timer; + +bool WTX_process(int read_timeout); + +void WTX_clear() +{ + WTX_sent = false; + WTX_fail = false; + WTX_timer = 0; +} + +bool WTX_on(int WTX_time) +{ + WTX_clear(); + WTX_timer = millis(); + + return true; +} + +bool WTX_off() +{ + WTX_timer = 0; + + // read data if we sent WTX + if (WTX_sent) + { + if (!WTX_process(100)) + { + printf1(TAG_NFC, "WTX-off get last WTX error\n"); + return false; + } + } + + if (WTX_fail) + { + printf1(TAG_NFC, "WTX-off fail\n"); + return false; + } + + WTX_clear(); + return true; +} + +void WTX_timer_exec() +{ + // condition: (timer on) or (not expired[300ms]) + if ((WTX_timer <= 0) || WTX_timer + 300 > millis()) + return; + + WTX_process(10); + WTX_timer = millis(); +} + +// executes twice a period. 1st for send WTX, 2nd for check the result +// read timeout must be 10 ms to call from interrupt +bool WTX_process(int read_timeout) +{ + uint8_t wtx[] = {0xf2, 0x01}; + if (WTX_fail) + return false; + + if (!WTX_sent) + { + nfc_write_frame(wtx, sizeof(wtx)); + WTX_sent = true; + return true; + } + else + { + uint8_t data[32]; + int len; + if (!ams_receive_with_timeout(read_timeout, data, sizeof(data), &len)) + { + WTX_fail = true; + return false; + } + + if (len != 2 || data[0] != 0xf2 || data[1] != 0x01) + { + WTX_fail = true; + return false; + } + + WTX_sent = false; + return true; + } +} + +int answer_rats(uint8_t parameter) +{ + + uint8_t fsdi = (parameter & 0xf0) >> 4; + uint8_t cid = (parameter & 0x0f); + + NFC_STATE.cid = cid; + + if (fsdi == 0) + NFC_STATE.max_frame_size = 16; + else if (fsdi == 1) + NFC_STATE.max_frame_size = 24; + else + NFC_STATE.max_frame_size = 32; + + uint8_t res[3 + 11]; + res[0] = sizeof(res); + res[1] = 2 | (1<<5); // 2 FSCI == 32 byte frame size, TB is enabled + + // frame wait time = (256 * 16 / 13.56MHz) * 2^FWI + // FWI=0, FMT=0.3ms (min) + // FWI=4, FMT=4.8ms (default) + // FWI=10, FMT=309ms + // FWI=12, FMT=1237ms + // FWI=14, FMT=4949ms (max) + res[2] = (12<<4) | (0); // TB (FWI << 4) | (SGTI) + + // historical bytes + memcpy(&res[3], (uint8_t *)"SoloKey tap", 11); + + + nfc_write_frame(res, sizeof(res)); + ams_wait_for_tx(10); + + + return 0; +} + +void rblock_acknowledge() +{ + uint8_t buf[32]; + NFC_STATE.block_num = !NFC_STATE.block_num; + buf[0] = NFC_CMD_RBLOCK | NFC_STATE.block_num; + nfc_write_frame(buf,1); +} + +// Selects application. Returns 1 if success, 0 otherwise +int select_applet(uint8_t * aid, int len) +{ + if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0) + { + NFC_STATE.selected_applet = APP_FIDO; + return APP_FIDO; + } + else if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0) + { + NFC_STATE.selected_applet = APP_NDEF_TYPE_4; + return APP_NDEF_TYPE_4; + } + else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0) + { + NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER; + return APP_CAPABILITY_CONTAINER; + } + else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0) + { + NFC_STATE.selected_applet = APP_NDEF_TAG; + return APP_NDEF_TAG; + } + return APP_NOTHING; +} + +void nfc_process_iblock(uint8_t * buf, int len) +{ + APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1); + uint8_t * payload = buf + 1 + 5; + uint8_t plen = apdu->lc; + int selected; + CTAP_RESPONSE ctap_resp; + int status; + + printf1(TAG_NFC,"Iblock: "); + dump_hex1(TAG_NFC, buf, len); + + // TODO this needs to be organized better + switch(apdu->ins) + { + case APDU_INS_SELECT: + if (plen > len - 6) + { + printf1(TAG_ERR, "Truncating APDU length %d\r\n", apdu->lc); + plen = len-6; + } + // if (apdu->p1 == 0 && apdu->p2 == 0x0c) + // { + // printf1(TAG_NFC,"Select NDEF\r\n"); + // + // NFC_STATE.selected_applet = APP_NDEF_TAG; + // // Select NDEF file! + // res[0] = NFC_CMD_IBLOCK | (buf[0] & 1); + // res[1] = SW_SUCCESS>>8; + // res[2] = SW_SUCCESS & 0xff; + // nfc_write_frame(res, 3); + // printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC,res, 3); + // } + // else + { + selected = select_applet(payload, plen); + if (selected == APP_FIDO) + { + // block = buf[0] & 1; + // block = NFC_STATE.block_num; + // block = !block; + // NFC_STATE.block_num = block; + // NFC_STATE.block_num = block; + nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + printf1(TAG_NFC, "FIDO applet selected.\r\n"); + } + else if (selected != APP_NOTHING) + { + nfc_write_response(buf[0], SW_SUCCESS); + printf1(TAG_NFC, "SELECTED %d\r\n", selected); + } + else + { + nfc_write_response(buf[0], SW_FILE_NOT_FOUND); + printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,payload, plen); + } + } + break; + + case APDU_FIDO_U2F_VERSION: + if (NFC_STATE.selected_applet != APP_FIDO) { + nfc_write_response(buf[0], SW_INS_INVALID); + break; + } + + printf1(TAG_NFC, "U2F GetVersion command.\r\n"); + + nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + break; + + case APDU_FIDO_U2F_REGISTER: + if (NFC_STATE.selected_applet != APP_FIDO) { + nfc_write_response(buf[0], SW_INS_INVALID); + break; + } + + printf1(TAG_NFC, "U2F Register command.\r\n"); + + if (plen != 64) + { + printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen); + nfc_write_response(buf[0], SW_WRONG_LENGTH); + return; + } + + timestamp(); + + + // WTX_on(WTX_TIME_DEFAULT); + // SystemClock_Config_LF32(); + // delay(300); + device_set_clock_rate(DEVICE_LOW_POWER_FAST);; + u2f_request_nfc(&buf[1], len, &ctap_resp); + device_set_clock_rate(DEVICE_LOW_POWER_IDLE);; + // if (!WTX_off()) + // return; + + printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp()); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + + // printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); + + + + + printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp()); + break; + + case APDU_FIDO_U2F_AUTHENTICATE: + if (NFC_STATE.selected_applet != APP_FIDO) { + nfc_write_response(buf[0], SW_INS_INVALID); + break; + } + + printf1(TAG_NFC, "U2F Authenticate command.\r\n"); + + if (plen != 64 + 1 + buf[6 + 64]) + { + delay(5); + printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]); + nfc_write_response(buf[0], SW_WRONG_LENGTH); + return; + } + + timestamp(); + // WTX_on(WTX_TIME_DEFAULT); + u2f_request_nfc(&buf[1], len, &ctap_resp); + // if (!WTX_off()) + // return; + + printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); + printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp()); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp); + break; + + case APDU_FIDO_NFCCTAP_MSG: + if (NFC_STATE.selected_applet != APP_FIDO) { + nfc_write_response(buf[0], SW_INS_INVALID); + break; + } + + printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp()); + + WTX_on(WTX_TIME_DEFAULT); + ctap_response_init(&ctap_resp); + status = ctap_request(payload, plen, &ctap_resp); + if (!WTX_off()) + return; + + printf1(TAG_NFC, "CTAP resp: 0x%02� len: %d\r\n", status, ctap_resp.length); + + if (status == CTAP1_ERR_SUCCESS) + { + memmove(&ctap_resp.data[1], &ctap_resp.data[0], ctap_resp.length); + ctap_resp.length += 3; + } else { + ctap_resp.length = 3; + } + ctap_resp.data[0] = status; + ctap_resp.data[ctap_resp.length - 2] = SW_SUCCESS >> 8; + ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff; + + printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp()); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp()); + break; + + case APDU_INS_READ_BINARY: + + + switch(NFC_STATE.selected_applet) + { + case APP_CAPABILITY_CONTAINER: + printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n"); + if (plen > 15) + { + printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc); + plen = 15; + } + nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, plen, SW_SUCCESS); + ams_wait_for_tx(10); + break; + case APP_NDEF_TAG: + printf1(TAG_NFC,"APP_NDEF_TAG\r\n"); + if (plen > (sizeof(NDEF_SAMPLE) - 1)) + { + printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc); + plen = sizeof(NDEF_SAMPLE) - 1; + } + nfc_write_response_ex(buf[0], NDEF_SAMPLE, plen, SW_SUCCESS); + ams_wait_for_tx(10); + break; + default: + printf1(TAG_ERR, "No binary applet selected!\r\n"); + return; + break; + } + + break; + default: + printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins); + nfc_write_response(buf[0], SW_INS_INVALID); + break; + } + + +} + +static uint8_t ibuf[1024]; +static int ibuflen = 0; + +void clear_ibuf() +{ + ibuflen = 0; + memset(ibuf, 0, sizeof(ibuf)); +} + +void nfc_process_block(uint8_t * buf, unsigned int len) +{ + + if (!len) + return; + + if (IS_PPSS_CMD(buf[0])) + { + printf1(TAG_NFC, "NFC_CMD_PPSS\r\n"); + } + else if (IS_IBLOCK(buf[0])) + { + if (buf[0] & 0x10) + { + printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len); + if (ibuflen + len > sizeof(ibuf)) + { + printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf)); + nfc_write_response(buf[0], SW_INTERNAL_EXCEPTION); + return; + } + + printf1(TAG_NFC_APDU,"i> "); + dump_hex1(TAG_NFC_APDU, buf, len); + + if (len) + { + memcpy(&ibuf[ibuflen], &buf[1], len - 1); + ibuflen += len - 1; + } + + // send R block + uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3); + nfc_write_frame(&rb, 1); + } else { + if (ibuflen) + { + if (len) + { + memcpy(&ibuf[ibuflen], &buf[1], len - 1); + ibuflen += len - 1; + } + + memmove(&ibuf[1], ibuf, ibuflen); + ibuf[0] = buf[0]; + ibuflen++; + + printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len); + + printf1(TAG_NFC_APDU,"i> "); + dump_hex1(TAG_NFC_APDU, buf, len); + + nfc_process_iblock(ibuf, ibuflen); + } else { + // printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n"); + nfc_process_iblock(buf, len); + } + clear_ibuf(); + } + } + else if (IS_RBLOCK(buf[0])) + { + rblock_acknowledge(); + printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n"); + } + else if (IS_SBLOCK(buf[0])) + { + + if ((buf[0] & NFC_SBLOCK_DESELECT) == 0) + { + printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n"); + nfc_write_frame(buf, 1); + ams_wait_for_tx(2); + ams_write_command(AMS_CMD_SLEEP); + nfc_state_init(); + clear_ibuf(); + WTX_clear(); + } + else + { + printf1(TAG_NFC, "NFC_CMD_SBLOCK, Unknown. len[%d]\r\n", len); + } + dump_hex1(TAG_NFC, buf, len); + } + else + { + printf1(TAG_NFC, "unknown NFC request\r\n len[%d]:", len); + dump_hex1(TAG_NFC, buf, len); + } +} + +int nfc_loop() +{ + uint8_t buf[32]; + AMS_DEVICE ams; + int len = 0; + + + read_reg_block(&ams); + uint8_t state = AMS_STATE_MASK & ams.regs.rfid_status; + + if (state != AMS_STATE_SELECTED && state != AMS_STATE_SELECTEDX) + { + // delay(1); // sleep ? + return 0; + } + + if (ams.regs.rfid_status) + { + // if (state != AMS_STATE_SENSE) + // printf1(TAG_NFC," %s x%02x\r\n", ams_get_state_string(ams.regs.rfid_status), state); + } + if (ams.regs.int0 & AMS_INT_INIT) + { + nfc_state_init(); + } + if (ams.regs.int1) + { + // ams_print_int1(ams.regs.int1); + } + + if ((ams.regs.int0 & AMS_INT_RXE)) + { + if (ams.regs.buffer_status2) + { + if (ams.regs.buffer_status2 & AMS_BUF_INVALID) + { + printf1(TAG_NFC,"Buffer being updated!\r\n"); + } + else + { + len = ams.regs.buffer_status2 & AMS_BUF_LEN_MASK; + ams_read_buffer(buf, len); + } + } + } + + if (len) + { + + // ISO 14443-3 + switch(buf[0]) + { + case NFC_CMD_REQA: + printf1(TAG_NFC, "NFC_CMD_REQA\r\n"); + break; + case NFC_CMD_WUPA: + printf1(TAG_NFC, "NFC_CMD_WUPA\r\n"); + break; + case NFC_CMD_HLTA: + printf1(TAG_NFC, "HLTA/Halt\r\n"); + break; + case NFC_CMD_RATS: + + answer_rats(buf[1]); + + NFC_STATE.block_num = 1; + clear_ibuf(); + WTX_clear(); + break; + default: + + // ISO 14443-4 + nfc_process_block(buf,len); + + + break; + } + + } + + return len; + +} diff --git a/targets/stm32l432/src/nfc.h b/targets/stm32l432/src/nfc.h new file mode 100644 index 0000000..a8627a2 --- /dev/null +++ b/targets/stm32l432/src/nfc.h @@ -0,0 +1,64 @@ +#ifndef _NFC_H_ +#define _NFC_H_ + +#include +#include +#include "apdu.h" + +// Return number of bytes read if any. +int nfc_loop(); + +bool nfc_init(); + +typedef struct +{ + uint8_t cclen_hi; + uint8_t cclen_lo; + uint8_t version; + uint8_t MLe_hi; + uint8_t MLe_lo; + uint8_t MLc_hi; + uint8_t MLc_lo; + uint8_t tlv[8]; +} __attribute__((packed)) CAPABILITY_CONTAINER; + +// WTX time in ms +#define WTX_TIME_DEFAULT 300 + +#define NFC_CMD_REQA 0x26 +#define NFC_CMD_WUPA 0x52 +#define NFC_CMD_HLTA 0x50 +#define NFC_CMD_RATS 0xe0 + +#define NFC_CMD_PPSS 0xd0 +#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS) +#define NFC_CMD_IBLOCK 0x00 +#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) ) +#define NFC_CMD_RBLOCK 0x80 +#define NFC_CMD_RBLOCK_ACK 0x20 +#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) ) +#define NFC_CMD_SBLOCK 0xc0 +#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) ) + +#define NFC_SBLOCK_DESELECT 0x30 +#define NFC_SBLOCK_WTX 0x30 + +#define AID_NDEF_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x01" +#define AID_NDEF_MIFARE_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x00" +#define AID_CAPABILITY_CONTAINER "\xE1\x03" +#define AID_NDEF_TAG "\xE1\x04" +#define AID_FIDO "\xa0\x00\x00\x06\x47\x2f\x00\x01" + +typedef enum +{ + APP_NOTHING = 0, + APP_NDEF_TYPE_4 = 1, + APP_MIFARE_TYPE_4, + APP_CAPABILITY_CONTAINER, + APP_NDEF_TAG, + APP_FIDO, +} APPLETS; + +void WTX_timer_exec(); + +#endif diff --git a/targets/stm32l432/src/redirect.c b/targets/stm32l432/src/redirect.c index 3af360f..ed4147f 100644 --- a/targets/stm32l432/src/redirect.c +++ b/targets/stm32l432/src/redirect.c @@ -24,19 +24,33 @@ void _putchar(char c) } - -int _write (int fd, const void *buf, long int len) +int _write (int fd, const void *buf, unsigned long int len) { uint8_t * data = (uint8_t *) buf; +#if DEBUG_LEVEL>1 + static uint8_t logbuf[1000] = {0}; + static int logbuflen = 0; + if (logbuflen + len > sizeof(logbuf)) { + int mlen = logbuflen + len - sizeof(logbuf); + memmove(logbuf, &logbuf[mlen], sizeof(logbuf) - mlen); + logbuflen -= mlen; + } + memcpy(&logbuf[logbuflen], data, len); + logbuflen += len; - // Send out USB serial - CDC_Transmit_FS(data, len); - + // Send out USB serial + uint8_t res = CDC_Transmit_FS(logbuf, logbuflen); + if (res == USBD_OK) + logbuflen = 0; +#endif +#ifdef ENABLE_SERIAL_PRINTING // Send out UART serial while(len--) { _putchar(*data++); } +#endif return 0; + } #endif diff --git a/targets/stm32l432/src/startup_stm32l432xx.s b/targets/stm32l432/src/startup_stm32l432xx.s index 32d257f..7599702 100644 --- a/targets/stm32l432/src/startup_stm32l432xx.s +++ b/targets/stm32l432/src/startup_stm32l432xx.s @@ -7,7 +7,7 @@ * - Set the initial SP * - Set the initial PC == Reset_Handler, * - Set the vector table entries with the exceptions ISR address, - * - Configure the clock system + * - Configure the clock system * - Branches to main in the C library (which eventually * calls main()). * After Reset the Cortex-M4 processor is in Thread mode, @@ -79,6 +79,8 @@ Reset_Handler: ldr sp, =_estack /* Atollic update: set stack pointer */ /* Copy the data segment initializers from flash to SRAM */ +/* Call the clock system intitialization function.*/ + bl SystemInit movs r1, #0 b LoopCopyDataInit @@ -106,8 +108,7 @@ LoopFillZerobss: cmp r2, r3 bcc FillZerobss -/* Call the clock system intitialization function.*/ - bl SystemInit + /* Call static constructors */ bl __libc_init_array /* Call the application's entry point.*/ @@ -115,7 +116,7 @@ LoopFillZerobss: LoopForever: b LoopForever - + .size Reset_Handler, .-Reset_Handler /** @@ -414,49 +415,49 @@ g_pfnVectors: .weak COMP_IRQHandler .thumb_set COMP_IRQHandler,Default_Handler - + .weak LPTIM1_IRQHandler .thumb_set LPTIM1_IRQHandler,Default_Handler - + .weak LPTIM2_IRQHandler - .thumb_set LPTIM2_IRQHandler,Default_Handler - + .thumb_set LPTIM2_IRQHandler,Default_Handler + .weak USB_IRQHandler - .thumb_set USB_IRQHandler,Default_Handler - + .thumb_set USB_IRQHandler,Default_Handler + .weak DMA2_Channel6_IRQHandler - .thumb_set DMA2_Channel6_IRQHandler,Default_Handler - + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + .weak DMA2_Channel7_IRQHandler - .thumb_set DMA2_Channel7_IRQHandler,Default_Handler - + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + .weak LPUART1_IRQHandler - .thumb_set LPUART1_IRQHandler,Default_Handler - + .thumb_set LPUART1_IRQHandler,Default_Handler + .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler - + .thumb_set QUADSPI_IRQHandler,Default_Handler + .weak I2C3_EV_IRQHandler - .thumb_set I2C3_EV_IRQHandler,Default_Handler - + .thumb_set I2C3_EV_IRQHandler,Default_Handler + .weak I2C3_ER_IRQHandler - .thumb_set I2C3_ER_IRQHandler,Default_Handler - + .thumb_set I2C3_ER_IRQHandler,Default_Handler + .weak SAI1_IRQHandler .thumb_set SAI1_IRQHandler,Default_Handler - + .weak SWPMI1_IRQHandler .thumb_set SWPMI1_IRQHandler,Default_Handler - + .weak TSC_IRQHandler .thumb_set TSC_IRQHandler,Default_Handler - + .weak RNG_IRQHandler .thumb_set RNG_IRQHandler,Default_Handler - + .weak FPU_IRQHandler .thumb_set FPU_IRQHandler,Default_Handler - + .weak CRS_IRQHandler .thumb_set CRS_IRQHandler,Default_Handler /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/targets/stm32l432/src/system_stm32l4xx.c b/targets/stm32l432/src/system_stm32l4xx.c index 44f5432..a903c1c 100644 --- a/targets/stm32l432/src/system_stm32l4xx.c +++ b/targets/stm32l432/src/system_stm32l4xx.c @@ -106,6 +106,8 @@ */ #include "stm32l4xx.h" +#include "device.h" +#include "init.h" #if !defined (HSE_VALUE) #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ @@ -219,6 +221,8 @@ void SystemInit(void) /* Disable all interrupts */ RCC->CIER = 0x00000000U; + device_set_clock_rate(DEVICE_LOW_POWER_IDLE); + } /**