/** ******************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * All rights reserved. * * This software component is licensed by WCH under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ******************************************************************************* */ #include "pins_arduino.h" #include "mik32_hal_adc.h" #include "wiring_analog.h" #include "wiring_LL.h" #define SPI0_SWITCH_PORT GPIO_1 #define SPI0_SWITCH_PIN GPIO_PIN_10 #define SPI0_NSS_IN_PORT GPIO_0 #define SPI0_NSS_IN_PIN GPIO_PIN_3 #define SPI0_NSS_OUT_PORT GPIO_1 #define SPI0_NSS_OUT_PIN GPIO_PIN_14 #define SPI1_SWITCH_PORT GPIO_1 #define SPI1_SWITCH_PIN GPIO_PIN_6 #define SPI1_NSS_IN_PORT GPIO_1 #define SPI1_NSS_IN_PIN GPIO_PIN_3 #define SPI1_NSS_OUT_PORT GPIO_1 #define SPI1_NSS_OUT_PIN GPIO_PIN_4 bool spi0NssPinIsBlocked = false; bool spi1NssPinIsBlocked = false; // list of pin numbers from both ports with pins inside the port const HAL_PinsTypeDef digitalPinToGpioPinArray[] = { GPIO_PIN_5, // D0 GPIO_PIN_6, // D1 GPIO_PIN_10,// D2 GPIO_PIN_0, // D3 GPIO_PIN_8, // D4 GPIO_PIN_1, // D5 GPIO_PIN_2, // D6 GPIO_PIN_8, // D7 GPIO_PIN_9, // D8 GPIO_PIN_3, // D9 GPIO_PIN_3, // D10 GPIO_PIN_1, // D11 GPIO_PIN_0, // D12 GPIO_PIN_2, // D13 GPIO_PIN_5, // D14/A0 GPIO_PIN_7, // D15/A1 GPIO_PIN_4, // D16/A2 GPIO_PIN_7, // D17/A3 GPIO_PIN_12,// D18 GPIO_PIN_13,// D19 GPIO_PIN_9, // A4 (pin 20) GPIO_PIN_9, // A5 (pin 21) GPIO_PIN_7, // LED(pin 22) 0, // dummy pin for backward compatibility with ace-uno GPIO_PIN_9, // A6 (pin 24) GPIO_PIN_9, // A7 (pin 25) }; // determines the address of the port by the board pin number to which this pin belongs on the MCU GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber) { GPIO_TypeDef* gpioNum = NULL; if (digPinNumber >= pinCommonQty()) { ErrorMsgHandler("digitalPinToPort(): pin number exceeds the total number of pins"); return NULL; } // port 2 - led (22) if (digPinNumber == LED_BUILTIN) gpioNum = GPIO_2; // port 1 - board pins 7, 8, 10...13, 14(А0), 15(А1), 18,19 else if (digPinNumber == 7 || digPinNumber == 8 || (digPinNumber >= 10 && digPinNumber <= 15) || digPinNumber == 18 || digPinNumber == 19 || (digPinNumber == 9 && spi0NssPinIsBlocked)) gpioNum = GPIO_1; // port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5), 24(A6), 25(A7) else gpioNum = GPIO_0; return gpioNum; } // determines the pin address inside the port by the board pin number HAL_PinsTypeDef digitalPinToBitMask(uint32_t digPinNumber) { if (digPinNumber >= pinCommonQty()) { ErrorMsgHandler("digitalPinToBitMask(): pin number exceeds the total number of pins"); return NC; } HAL_PinsTypeDef mask; // if spi is on default pin NSS_IN is needed for spi, board pin is replaced to pin NSS_OUT if ((digPinNumber == 10) && spi1NssPinIsBlocked) mask = SPI1_NSS_OUT_PIN; else if ((digPinNumber == 9) && spi0NssPinIsBlocked) mask = SPI0_NSS_OUT_PIN; else mask = digitalPinToGpioPinArray[digPinNumber]; return mask; } uint16_t pinCommonQty(void) { return (uint16_t)(sizeof(digitalPinToGpioPinArray)/sizeof(digitalPinToGpioPinArray[0])); } // the function returns a reference to the OUTPUT address of the GPIO register volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x) { return &GPIO_x->OUTPUT_; } // the function returns a reference to the STATE address of the GPIO register volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x) { return &GPIO_x->STATE; } // the function initializes additional MCU pins depending on the specified pin number #define SELA_A_PORT GPIO_1 #define SELA_A_PIN GPIO_PIN_15 #define SELA_B_PORT GPIO_1 #define SELA_B_PIN GPIO_PIN_11 static bool selaSwitchesIsInited = false; void additionalPinsInit(uint32_t PinNumber) { // init switches if (!selaSwitchesIsInited) { // SELA_A HAL_GPIO_PinConfig(SELA_A_PORT, SELA_A_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); // SELA_B HAL_GPIO_PinConfig(SELA_B_PORT, SELA_B_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); selaSwitchesIsInited = true; } if (PinNumber == A4) { HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_LOW); HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_LOW); } else if(PinNumber == A5) { HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_LOW); } else if(PinNumber == A6) { HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_LOW); HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); } else if(PinNumber == A7) { HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); } } void additionalPinsDeinit(uint32_t PinNumber) { if (PinNumber == A4 || PinNumber == A5) { // select A7 via switches selaA, selaB to allow using A4 and A5 as digital outputs HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); } } // ---------------------- ADC ---------------------- // // determines the ADC channel number by the board pin number uint32_t analogInputToChannelNumber(uint32_t PinNumber) { uint32_t adcChannel = 0; // if get a value 0...5 instead of A0...A7 if (PinNumber < 4) PinNumber += 14; // A0...A3 else if (PinNumber < 6) PinNumber += 16; // A4, A5 else if (PinNumber < 8) PinNumber += 18; // A6, A7 switch (PinNumber) { case PIN_A0: adcChannel = ADC_CHANNEL0; break; case PIN_A1: adcChannel = ADC_CHANNEL1; break; case PIN_A2: adcChannel = ADC_CHANNEL3; break; case PIN_A3: adcChannel = ADC_CHANNEL4; break; case PIN_A4: case PIN_A5: case PIN_A6: case PIN_A7: adcChannel = ADC_CHANNEL5; break; default: adcChannel = NC; } return adcChannel; } // ---------------------- PWM ---------------------- // // use only if digitalPinHasPWM() == true #define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)||(pin==12)||(pin==13)) ? 1:0) // use only if digitalPinHasPWM() == true // return true if digitalPin configured as pwm bool digitalPinPwmIsOn(uint8_t digitalPin) { uint8_t config = 0; uint8_t pinShift = PIN_MASK_TO_PIN_NUMBER(digitalPinToBitMask(digitalPin)); if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); else config = PIN_GET_PAD_CONFIG(PORT_1_CFG, pinShift); if (config == 2) return true; else return false; } bool digitalPinHasPWM(uint8_t p) { bool ret = false; // if spi is in use D10 cannot work as pwm if (((p == 9) && spi0NssPinIsBlocked) || ((p == 10) && spi1NssPinIsBlocked)) ret = false; else if (p == 3 || p == 5 || p == 6 || (p >= 9 && p <= 13)) ret = true; return ret; } // function is used only if digitalPinHasPWM() is true TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber) { TIMER32_TypeDef* timerNum = NULL; // timer 1 if (digPinNumber == 3 || digPinNumber == 5 || digPinNumber == 6 || digPinNumber == 9) timerNum = TIMER32_1; // timer 2 else if ((digPinNumber >= 10) && (digPinNumber <= 13)) timerNum = TIMER32_2; return timerNum; } // function is used only if digitalPinHasPWM() is true HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) { HAL_TIMER32_CHANNEL_IndexTypeDef channel = 0; if (digPinNumber == 3 || digPinNumber == 12) channel = TIMER32_CHANNEL_0; else if (digPinNumber == 5 || digPinNumber == 11) channel = TIMER32_CHANNEL_1; else if (digPinNumber == 6 || digPinNumber == 13) channel = TIMER32_CHANNEL_2; else if (digPinNumber == 9 || digPinNumber == 10) channel = TIMER32_CHANNEL_3; return channel; } // ---------------------- interrupts ---------------------- // // interrupt table is stored in ram to improve performance // index = interrupt number. In each row {digitalPinNumber, IntLineValue, IntMuxValue} uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3] = { { 2, GPIO_LINE_2, GPIO_MUX_LINE_2_PORT0_10}, // INT0 { 3, GPIO_LINE_0, GPIO_MUX_LINE_0_PORT0_0}, // INT1 { 4, GPIO_LINE_4, GPIO_MUX_LINE_4_PORT0_8}, // INT2 { 5, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT0_1}, // INT3 { 6, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT0_2}, // INT4 { 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT5 { 9, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT0_3}, // INT6 { A1, GPIO_LINE_7, GPIO_MUX_LINE_7_PORT1_7}, // INT7 }; int8_t digitalPinToGpioIntMux(uint8_t digPinNumber) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { if (interruptInfo[i][0] == digPinNumber) return interruptInfo[i][2]; } return NOT_AN_INTERRUPT; } int8_t digitalPinToGpioIntLine(uint8_t digPinNumber) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { if (interruptInfo[i][0] == digPinNumber) return interruptInfo[i][1]; } return NOT_AN_INTERRUPT; } int8_t gpioIntLineToInterrupt(uint32_t gpioIntLine) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { if (interruptInfo[i][1] == gpioIntLine) return i; } return NOT_AN_INTERRUPT; } int8_t digitalPinToInterrupt(uint32_t digPinNumber) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { if (interruptInfo[i][0] == digPinNumber) return i; } return NOT_AN_INTERRUPT; } // ---------------------- SPI ---------------------- // void spi_onBegin(uint8_t spiNum) { // On Elbear Nano spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work (NSS_IN). // This pins are connected to board digital pins D9 and D10. There is a seller on each pin which // replace board digital pin from NSS_IN pin to different free pin (NSS_OUT) // replace config from NSS_IN to NSS_OUT uint8_t config; if (spiNum == 1) config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)); else config = PIN_GET_PAD_CONFIG(PORT_0_CFG, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)); if (config == 0) // common gpio { if (spiNum == 1) { // get info from pin NSS_IN and set config to NSS_OUT HAL_GPIO_PinConfig(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN), (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)), HAL_GPIO_DS_2MA); HAL_GPIO_WritePin(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN))); // pin D10 was switched to different gpio and can be used further } else { // get info from pin NSS_IN and set config to NSS_OUT HAL_GPIO_PinConfig(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN), (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_0_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)), HAL_GPIO_DS_2MA); HAL_GPIO_WritePin(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN))); // pin D9 was switched to different gpio and can be used further } } else if(config == 2) // timer for pwm { // if spi NSS_IN pin was used as pwm, we need to stop timer, because another pins don't support it if (spiNum == 1) { analogWriteStop(10); ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); } else { analogWriteStop(9); ErrorMsgHandler("analogWrite(): D9 cannot be used as PWM pin while SPI1 is running"); } } // switch seller to pin NSS_OUT if (spiNum == 1) { HAL_GPIO_PinConfig(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); HAL_GPIO_WritePin (SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_HIGH); spi1NssPinIsBlocked = true; // block spi pin } else { HAL_GPIO_PinConfig(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); HAL_GPIO_WritePin (SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_HIGH); spi0NssPinIsBlocked = true; // block spi pin } } void spi_onEnd(uint8_t spiNum) { // get info from pin NSS_OUT and set config to NSS_IN if (spiNum == 1) { HAL_GPIO_PinConfig(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN), (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); HAL_GPIO_WritePin (SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN))); // switch seller back to NSS_IN HAL_GPIO_WritePin(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_LOW); spi1NssPinIsBlocked = false; // unblock spi pin } else { HAL_GPIO_PinConfig(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN), (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); HAL_GPIO_WritePin (SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN))); // switch seller back to NSS_IN HAL_GPIO_WritePin(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_LOW); spi0NssPinIsBlocked = false; // unblock spi pin } }