diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index d69071f..64bf587 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -4,6 +4,7 @@ #include "pins_arduino.h" #include "wiring_digital.h" #include "WInterrupts.h" +#include "wiring_LL.h" extern void ErrorMsgHandler(const char * msg); @@ -100,33 +101,27 @@ void detachInterrupt(uint8_t interruptNum) void disableInterrupt(uint8_t interruptNum) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) - { - int irq_line_num = interruptToGpioIntLine(interruptNum) >> GPIO_IRQ_LINE_S; // disable gpio interrupt line - GPIO_IRQ->ENABLE_CLEAR = (1 << irq_line_num); - } + GPIO_IRQ_LINE_DISABLE(interruptToGpioIntLine(interruptNum)); } // enable single interrupt void enableInterrupt(uint8_t interruptNum) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) - { - int irq_line_num = interruptToGpioIntLine(interruptNum) >> GPIO_IRQ_LINE_S; // enable gpio interrupt line - GPIO_IRQ->ENABLE_SET = (1 << irq_line_num); - } + GPIO_IRQ_LINE_ENABLE(interruptToGpioIntLine(interruptNum)); } // common gpio interrupt handler +void gpio_interrupts_handler(void) __attribute__((noinline, section(".ram_text"))); void gpio_interrupts_handler(void) { // go through all the interrupts and call the handler for the triggered line for (uint8_t i = 0; i < EXTERNAL_NUM_INTERRUPTS; i++) { - if (HAL_GPIO_LineInterruptState(interruptToGpioIntLine(i))) + if (GPIO_IRQ_LINE_STATE(interruptToGpioIntLine(i))) intFunc[i](); } - - HAL_GPIO_ClearInterrupts(); + GPIO_IRQ_CLEAR_ALL(); } \ No newline at end of file diff --git a/cores/arduino/trap_handler.c b/cores/arduino/trap_handler.c index dc8ecd2..712913c 100644 --- a/cores/arduino/trap_handler.c +++ b/cores/arduino/trap_handler.c @@ -1,8 +1,5 @@ #include "mik32_hal_irq.h" -#include "mik32_hal_gpio.h" - - // isr functions extern void serial_handler_wrapper(uint8_t uartNumInt); extern void gpio_interrupts_handler(void); @@ -11,16 +8,13 @@ void __attribute__((weak)) wire_handler_wrapper(void) { // dummy function for case when wire library is not in use } -extern void softSerial_handler_wrapper(void); // ---------------------------------------------- // void __attribute__((noinline, section(".ram_text"))) trap_handler(void) { - ((GPIO_0)->CLEAR = (GPIO_PIN_0)); // gpio interrupt if (EPIC_CHECK_GPIO_IRQ()) - // gpio_interrupts_handler(); - softSerial_handler_wrapper(); + gpio_interrupts_handler(); // tone timer interrupt if (EPIC_CHECK_TIMER16_1()) @@ -40,5 +34,4 @@ void __attribute__((noinline, section(".ram_text"))) trap_handler(void) // reset all interrupts HAL_EPIC_Clear(0xFFFFFFFF); - ((GPIO_0)->SET = (GPIO_PIN_0)); } diff --git a/cores/arduino/wiring_LL.h b/cores/arduino/wiring_LL.h index fec4efe..84ba3c7 100644 --- a/cores/arduino/wiring_LL.h +++ b/cores/arduino/wiring_LL.h @@ -16,14 +16,18 @@ set_csr(mie, MIE_MEIE) // ----------------- GPIO ----------------- // -#define GPIO_SET_PIN(GPIO_x, pin) ((GPIO_x)->SET = (pin)) -#define GPIO_CLEAR_PIN(GPIO_x, pin) ((GPIO_x)->CLEAR = (pin)) -#define GPIO_READ_PIN(GPIO_x, pin) (((GPIO_x)->SET & (pin)) != (uint32_t)GPIO_PIN_LOW ? GPIO_PIN_HIGH : GPIO_PIN_LOW) +#define GPIO_SET_PIN(GPIO_x, pin) ((GPIO_x)->SET = (pin)) +#define GPIO_CLEAR_PIN(GPIO_x, pin) ((GPIO_x)->CLEAR = (pin)) +#define GPIO_READ_PIN(GPIO_x, pin) (((GPIO_x)->SET & (pin)) != (uint32_t)GPIO_PIN_LOW ? GPIO_PIN_HIGH : GPIO_PIN_LOW) // ----------------- GPIO IRQ ----------------- // -#define GPIO_IRQ_LINE_ENABLE(lineMask) ( GPIO_IRQ->ENABLE_SET = (1 << (lineMask >> GPIO_IRQ_LINE_S)) ) -#define GPIO_IRQ_LINE_DISABLE(lineMask) ( GPIO_IRQ->ENABLE_CLEAR = (1 << (lineMask >> GPIO_IRQ_LINE_S)) ) -#define GPIO_IRQ_CLEAR_ALL() (GPIO_IRQ->CLEAR = 0b11111111) +#define GPIO_IRQ_LINE_ENABLE(lineMask) ( GPIO_IRQ->ENABLE_SET = (1 << (lineMask >> GPIO_IRQ_LINE_S)) ) +#define GPIO_IRQ_LINE_DISABLE(lineMask) ( GPIO_IRQ->ENABLE_CLEAR = (1 << (lineMask >> GPIO_IRQ_LINE_S)) ) +#define GPIO_IRQ_LINE_STATE(lineMask) ((GPIO_IRQ->INTERRUPT & (1 << (lineMask >> GPIO_IRQ_LINE_S))) != 0) +#define GPIO_IRQ_CLEAR_ALL() ( GPIO_IRQ->CLEAR = 0b11111111) +// ----------------- PIN CONFIG ----------------- // +// return config of pin with pinShift(0...16) in portReg (config, pupd, ds for ports 0...2) +#define PIN_GET_PAD_CONFIG(portReg, pinShift) ((PAD_CONFIG->portReg >> (pinShift<<1)) & 0b11) #endif /* _WIRING_LL_H_ */ \ No newline at end of file diff --git a/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 0000000..ad9c143 --- /dev/null +++ b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,84 @@ +/* + Software serial multiple serial test + + Receives from the two software serial ports, + sends to the hardware serial port. + + In order to listen on a software port, you call port.listen(). + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the + buffer is empty. This example switches ports when there is nothing + more to read from a port + + The circuit: + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 2(RX), RX to pin 6(TX) + * Second serial device's TX attached to digital pin 8(RX), RX to pin 10(TX) + + Note: + Not all pins on the Elbear Ace-Uno support interrupts, + so only the following can be used for RX: + 2, 3, 4, 5, 8, 9 + + created 18 Apr. 2011 + modified 19 March 2016 + by Tom Igoe + based on Mikal Hart's twoPortRXExample + + This example code is in the public domain. + + */ + +#include +// software serial #1: RX = digital pin 2, TX = digital pin 6 +SoftwareSerial portOne(2, 6); + +// software serial #2: RX = digital pin 8, TX = digital pin 10 +SoftwareSerial portTwo(8, 10); + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // Start each software serial port + portOne.begin(57600); + portTwo.begin(57600); + + portTwo.listen(); + delay(2000); +} + +void loop() { + // By default, the last initialized port is listening. + // when you want to listen on a port, explicitly select it: + portOne.listen(); + Serial.println("Data from port one:"); + // while there is data coming in, read it + // and send to the hardware serial port: + while (portOne.available() > 0) { + char inByte = portOne.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); + delay(2000); + + // // Now listen on the second port + // portTwo.listen(); + // // while there is data coming in, read it + // // and send to the hardware serial port: + // Serial.println("Data from port two:"); + // while (portTwo.available() > 0) { + // char inByte = portTwo.read(); + // Serial.write(inByte); + // } + + // // blank line to separate data from the two ports: + // Serial.println(); + // delay(2000); +} diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index c2a320f..18d9b41 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -89,15 +89,13 @@ void SoftwareSerial::recv() // .ram_text bool rxState = (bool)GPIO_READ_PIN((GPIO_TypeDef *)_receivePortRegister, (HAL_PinsTypeDef)_receiveBitMask); if (_inverse_logic ? rxState : !rxState) { - // Disable further interrupts during reception, this prevents - // triggering another interrupt directly after we return, which can - // cause problems at higher baudrates. + // Disable further interrupts during reception, this prevents triggering another interrupt + // directly after we return, which can cause problems at higher baudrates. setRxIntMsk(false); // __always_inline__ // Wait approximately 1/2 of a bit width to "center" the sample if (_rx_delay_centering > 0) tunedDelay(_rx_delay_centering); // .ram_text - GPIO_0->OUTPUT_ ^= GPIO_PIN_1; // Read each of the 8 bits uint8_t data = 0; @@ -105,13 +103,9 @@ void SoftwareSerial::recv() // .ram_text { tunedDelay(_rx_delay_intrabit); data >>= 1; - - GPIO_0->OUTPUT_ ^= GPIO_PIN_1; - if (GPIO_READ_PIN((GPIO_TypeDef *)_receivePortRegister, (HAL_PinsTypeDef)_receiveBitMask)) data |= 0x80; } - if (_inverse_logic) data = ~data; @@ -124,17 +118,13 @@ void SoftwareSerial::recv() // .ram_text _receive_buffer_tail = next; } else - { _buffer_overflow = true; - } // skip the stop bit tunedDelay(_rx_delay_stopbit); - GPIO_0->OUTPUT_ ^= GPIO_PIN_1; // Re-enable interrupts when we're sure to be inside the stop bit setRxIntMsk(true); - } GPIO_IRQ_CLEAR_ALL(); } @@ -151,7 +141,7 @@ void SoftwareSerial::handle_interrupt() // .ram_text { if (active_object) { - active_object->recv(); + active_object->recv(); // .ram_text } } @@ -187,29 +177,33 @@ SoftwareSerial::~SoftwareSerial() void SoftwareSerial::setTX(uint8_t tx) { - // First configure then write because writing pin didn't work until config is applied + // save pin and port info + _transmitBitMask = (uint16_t)digitalPinToBitMask(tx); + _transmitPortRegister = (uint32_t)digitalPinToPort(tx); + // set state before tx pin initialization to prevent false start bit + if (_inverse_logic) + GPIO_CLEAR_PIN((GPIO_TypeDef *)_transmitPortRegister, (HAL_PinsTypeDef)_transmitBitMask); + else + GPIO_SET_PIN((GPIO_TypeDef *)_transmitPortRegister, (HAL_PinsTypeDef)_transmitBitMask); + // init pin as output pinMode(tx, OUTPUT); - digitalWrite(tx, _inverse_logic ? LOW : HIGH); - _transmitBitMask = (uint16_t)digitalPinToBitMask(tx); // save tx bit mask - _transmitPortRegister = (uint32_t)digitalPinToPort(tx); // save tx port adress } void SoftwareSerial::setRX(uint8_t rx) { - _receiveBitMask = (uint16_t)digitalPinToBitMask(rx); // save rx bit mask - _receivePortRegister = (uint32_t)digitalPinToPort(rx); // save rx port adress - if (!_inverse_logic) - pinMode(rx, INPUT_PULLUP); // pullup for normal logic - else - pinMode(rx, INPUT); - - // Save gpio_line for turning on/off interrupts + // save pin, port and gpio_line info + _receiveBitMask = (uint16_t)digitalPinToBitMask(rx); + _receivePortRegister = (uint32_t)digitalPinToPort(rx); _int_maskLine = digitalPinToGpioIntLine(_receivePin); - // Init interrupt line - HAL_GPIO_InitInterruptLine((HAL_GPIO_Line_Config)digitalPinToGpioIntMux(_receivePin), - _inverse_logic ? GPIO_INT_MODE_RISING : GPIO_INT_MODE_FALLING); - GPIO_IRQ_LINE_DISABLE(_int_maskLine); // turn off int line (it turning on while line init) - HAL_EPIC_MaskEdgeSet(HAL_EPIC_GPIO_IRQ_MASK); // turn on the mask in EPIC + + // attach interrupt to rx pin if available + attachInterrupt(digitalPinToInterrupt(_receivePin), softSerial_handler_wrapper, _inverse_logic ? RISING : FALLING); + if (!_inverse_logic) + // turn on pull up for rx if logic is not inverse + HAL_GPIO_PinConfig((GPIO_TypeDef *)_receivePortRegister, (HAL_PinsTypeDef)_receiveBitMask, + HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_UP, HAL_GPIO_DS_2MA); + // turn off int line for while (it turning on in attachInterrupt()) + GPIO_IRQ_LINE_DISABLE(_int_maskLine); } uint32_t SoftwareSerial::subtract_cap(uint32_t num, uint16_t sub) @@ -235,10 +229,11 @@ void SoftwareSerial::begin(long speed) // Precalculate the various delays in number of ticks uint32_t bit_delay = F_CPU / speed; + // init tx setTX(_transmitPin); _tx_delay = subtract_cap(bit_delay, 35); // 1 bit delay while transmitting data - // Only setup rx when we have a valid INT for this pin + // init rx only when we have a valid INT for this pin if (digitalPinToInterrupt(_receivePin) != NOT_AN_INTERRUPT) { // set pin config @@ -260,10 +255,6 @@ void SoftwareSerial::begin(long speed) tunedDelay(_tx_delay); // if we were low this establishes the end - // todo убрать - HAL_GPIO_PinConfig(GPIO_0, GPIO_PIN_0, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); - HAL_GPIO_PinConfig(GPIO_0, GPIO_PIN_1, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); - listen(); } @@ -363,4 +354,4 @@ int SoftwareSerial::peek() // Read from "head" return _receive_buffer[_receive_buffer_head]; -} +} \ No newline at end of file diff --git a/variants/standart/pins_arduino.h b/variants/standart/pins_arduino.h index 75d1ced..404f7da 100644 --- a/variants/standart/pins_arduino.h +++ b/variants/standart/pins_arduino.h @@ -109,7 +109,13 @@ static const uint8_t SCL = PIN_WIRE_SCL; #define WIRE_FREQ_1000K 1000000 // interrupts -extern const uint8_t interruptInfo[EXTERNAL_NUM_INTERRUPTS][3]; +extern uint8_t interruptInfo[EXTERNAL_NUM_INTERRUPTS][3]; +// determines the board pin number by interrupt number +#define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0]) +// determines gpio interrupt line by interrupt number +#define interruptToGpioIntLine(interruptNum) ((uint8_t)interruptInfo[interruptNum][1]) +// determines gpio interrupt mux by interrupt number +#define interruptToGpioIntMux(interruptNum) ((uint8_t)interruptInfo[interruptNum][2]) // determines interrupt number by the board pin number int8_t digitalPinToInterrupt(uint32_t digPinNumber); // determines interrupt number by the gpio interrupt line @@ -119,23 +125,8 @@ int8_t digitalPinToGpioIntMux(uint8_t digPinNumber); // determines gpio interrupt line by the board pin number int8_t digitalPinToGpioIntLine(uint8_t digPinNumber); -// determines the board pin number by interrupt number -inline uint8_t interruptToDigitalPin(uint8_t interruptNum) -{ - return interruptInfo[interruptNum][0]; -} -// determines gpio interrupt line by interrupt number -inline uint8_t interruptToGpioIntLine(uint8_t interruptNum) -{ - return (uint8_t)interruptInfo[interruptNum][1]; -} -// determines gpio interrupt mux by interrupt number -inline uint8_t interruptToGpioIntMux(uint8_t interruptNum) -{ - return (uint8_t)interruptInfo[interruptNum][2]; -} #ifdef __cplusplus } diff --git a/variants/standart/variant.c b/variants/standart/variant.c index 9608ab5..f5466c2 100644 --- a/variants/standart/variant.c +++ b/variants/standart/variant.c @@ -14,6 +14,7 @@ #include "pins_arduino.h" #include "mik32_hal_adc.h" #include "wiring_analog.h" +#include "wiring_LL.h" #ifdef __cplusplus extern "C" { @@ -107,10 +108,6 @@ volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x) return &GPIO_x->STATE; } -// return config of pin with pinShift(0...16) in portReg (config, pupd, ds for ports 0...2) -#define PIN_PAD_CONFIG(portReg, pinShift) ((PAD_CONFIG->portReg >> (pinShift<<1)) & 0b11) - - // ---------------------- ADC ---------------------- // // determines the ADC channel number by the board pin number uint32_t analogInputToChannelNumber(uint32_t PinNumber) @@ -168,9 +165,9 @@ bool digitalPinPwmIsOn(uint8_t digitalPin) uint8_t pinShift = pwmPinToGpioPinShift(digitalPin); if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) - config = PIN_PAD_CONFIG(PORT_0_CFG, pinShift); + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); else - config = PIN_PAD_CONFIG(PORT_1_CFG, pinShift); + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, pinShift); if (config == 2) return true; @@ -216,9 +213,9 @@ HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) } // ---------------------- interrupts ---------------------- // -// interrupt table +// interrupt table is stored in ram to improve performance // index = interrupt number. In each row {digitalPinNumber, IntLineValue, IntMuxValue} -const uint8_t interruptInfo[EXTERNAL_NUM_INTERRUPTS][3] = +uint8_t interruptInfo[EXTERNAL_NUM_INTERRUPTS][3] = { { 2, GPIO_LINE_2, GPIO_MUX_LINE_2_PORT0_10}, // INT0 { 3, GPIO_LINE_0, GPIO_MUX_LINE_0_PORT0_0}, // INT1 @@ -281,7 +278,7 @@ void spi_onBegin(void) // because spi needs pin 1.3 for correct work // replace config from 1.3 to 1.4 - uint8_t config = PIN_PAD_CONFIG(PORT_1_CFG, PIN_3_SHIFT); + uint8_t config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_3_SHIFT); if (config == 0) // common gpio { // get info from pin gpio1.3 and set config to gpio1.4