/** ******************************************************************************* * 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 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 bool spi0NssPinIsBlocked = false; bool spi1NssPinIsBlocked = false; // list of pin numbers from both ports with pins inside the port const HAL_PinsTypeDef digitalPinToGpioPinArray[PINS_COMMON_QTY] = { 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 (board pin 20) GPIO_PIN_9, // A5 (board pin 21) GPIO_PIN_7, // LED(pin 22) GPIO_PIN_6 // BTN(pin 23) }; // 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 SELA45_PORT GPIO_1 #define SELA45_PIN GPIO_PIN_15 static bool selaSwitchIsInited = false; void additionalPinsInit(uint32_t PinNumber) { if (!selaSwitchIsInited) { HAL_GPIO_PinConfig(SELA45_PORT, SELA45_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); selaSwitchIsInited = true; } // if we use pin A5, we need to set SELA45 to 1 to switch the output from A4 to A5 if (PinNumber == A5) HAL_GPIO_WritePin(SELA45_PORT, SELA45_PIN, GPIO_PIN_HIGH); else if(PinNumber == A4) // return the switch to A4 in case A5 was previously read HAL_GPIO_WritePin(SELA45_PORT, SELA45_PIN, GPIO_PIN_LOW); } // ---------------------- 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...A5 if (PinNumber < 4) PinNumber += 14; else if (PinNumber < 6) PinNumber += 16; 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: 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) { // if spi is in use D9 or D10 cannot work as pwm if (p == 3 || p == 5 || p == 6 || (p >= 11 && p <= 13) || ((p == 9) && !spi0NssPinIsBlocked) || ((p == 10) && !spi1NssPinIsBlocked)) return true; return false; } // 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 == 11 || digPinNumber == 12 || 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 { 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT4 { 9, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT0_3}, // INT5 { A1, GPIO_LINE_7, GPIO_MUX_LINE_7_PORT1_7}, // INT6 {BTN_BUILTIN, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT2_6}, // INT7 (button) }; 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 Ace-Uno rev1.1.0 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 } }