Многопоточность на AVR, это возможно?

Тема в разделе "Микроконтроллеры AVR", создана пользователем Алексей132, 11 июл 2019.

  1. b707

    b707 Гуру

    насколько я помню, вывод Serial.print() - блокирующий. На скорости 9600 вывод каждого символа занимает миллисекунду - а ТС у нас микросекунды ловит
     
  2. DetSimen

    DetSimen Guest

    Да, скорее, они его в deadlock ловят. Аркитехтура-то - неправильная.
     
  3. parovoZZ

    parovoZZ Гуру

    и зачем оно, если запись байта в UART производится оператором присвоения???
     
  4. parovoZZ

    parovoZZ Гуру

    я выводил с АЦП байты на скорости 70 000 байт в секунду через UART на скорости 250 000 baud в секунду. Потерь или тормозов замечено не было. Тактовая - всего 8МГц.
     
  5. ИгорьК

    ИгорьК Гуру

    Не может быть! Никто не выводил, и вот опять.
     
    Igor68 нравится это.
  6. ИгорьК

    ИгорьК Гуру

    upload_2019-7-11_13-48-51.png

    Уже просто мхом поросло от времени.
     
  7. parovoZZ

    parovoZZ Гуру

    это блокирующий вывод. А ТС нужен не блокирующий, т.е. работа на прерываниях.
     
  8. ИгорьК

    ИгорьК Гуру

    Мои тапки веселы, выражают благодарность и всяческое одобрение.
     
    Последнее редактирование: 11 июл 2019
  9. parovoZZ

    parovoZZ Гуру

    что-то типа такого:
    Код (C++):
        while (1)
        {
            if (node_in)
            {
                UART_Transmit(SPI_ReadByte());
                node_in = 0;
            }
        }
    Код (C++):
    ISR (SPI_STC_vect)
    {
        node_in = 1;
    }
     
    Алексей132 нравится это.
  10. SergeiL

    SergeiL Оракул Модератор

    Типа такого :) :

    Uart.c:
    Код (C++):
    /* UART Buffer Defines */
    #define UART_RX_BUFFER_SIZE 128 /* 1,2,4,8,16,32,64,128 or 256 bytes */
    #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
    #define UART_TX_BUFFER_SIZE 128 /* 1,2,4,8,16,32,64,128 or 256 bytes */
    #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )

    #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
    #error RX buffer size is not a power of 2
    #endif

    /* Static Variables */
    static unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
    static volatile unsigned char UART_RxHead;
    static volatile unsigned char UART_RxTail;
    static unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
    static volatile unsigned char UART_TxHead;
    static volatile unsigned char UART_TxTail;

    static volatile unsigned char Tx_Active_Flag;



    /* Read and write functions */
    unsigned char ReceiveByte( void )
    {
        unsigned char tmptail;

        while ( UART_RxHead == UART_RxTail ) /* wait for incomming data */
            ;
        tmptail = ( UART_RxTail + 1 ) & UART_RX_BUFFER_MASK;/* calculate buffer index */
        UART_RxTail = tmptail; /* store new index */
        return UART_RxBuf[tmptail]; /* return data */
    }

    void TransmitBytes( unsigned char *data,unsigned char leng )
    {
        unsigned char tmphead;
        unsigned char i;

        /* calculate buffer index */

        for (i=0;i<leng;i++)
        {
         tmphead = ( UART_TxHead + 1 ) & UART_TX_BUFFER_MASK;
            /* wait for free space in buffer */
         UART_TxBuf[tmphead] = *(data+i); /* store data in buffer */
         UART_TxHead = tmphead; /* store new index */
        }
        if (!Tx_Active_Flag)
        {
            UCSRB |= (1<<UDRIE); /* enable UDRE interrupt */
        }
    }

    unsigned char DataInReceiveBuffer( void )
    {
        return ( UART_RxHead != UART_RxTail );
            /* return 0 (FALSE) if the receive buffer is empty */
    }
    Uart.h:
    Код (C++):
    /* Prototypes */
    void InitUART( unsigned char baudrate );
    unsigned char ReceiveByte( void );
    void TransmitByte( unsigned char data );
    void TransmitBytes( unsigned char *data,unsigned char leng );
    main.c :
    Код (C++):

    /ICC-AVR
    // Target : M32
    // Crystal: 7.3728Mhz

    #include <iom32v.h>
    #include <macros.h>
    #include <stdio.h>
    #include <string.h>
    #include <eeprom.h>

    #include "my_macros.h"
    #include "LCD.c"
    #include "uart.h"
    #include "uart.c"
    #include "termo.h"
    #include "adam.c"
    // ....................................
    void init_devices(void)
    {
    //stop errant interrupts until set up
    CLI(); //disable all interrupts
    port_init();
    LCD_Init();    
    adc_init();
    uart0_init();
    timer0_init();
    timer1_init();
    timer2_init();

    MCUCR = 0x00;
    GICR  = 0x00;
    TIMSK = 0x01; // timer interrupt sources  было 01
    SEI(); //re-enable interrupts
    //all peripherals are now initialised
    }

    void main(void)
    {

         init_devices();

         while(1)
         {
    // .....................................
                       TransmitBytes(  out_err, strlen(out_err) );

    // ..................................
               
        }
    }
     
    Часть очень старого кода под Мегу32.
     
    ИгорьК нравится это.
  11. parovoZZ

    parovoZZ Гуру

    много воды....а обработчик прерывания не попал...
     
  12. SergeiL

    SergeiL Оракул Модератор

    Не воды, а того, без чего все это работать не будет.
    Пожалуйста:
    Код (C++):
    //UART0 initialisation
    // desired baud rate: 9600
    // actual: baud rate:9600 (0,0%)
    // char size: 8 bit
    // parity: Disabled
    void uart0_init(void)
    {
    UCSRA = 0x00;
    UCSRB = 0x00;          //disable while setting baud rate
    UCSRC = BIT(URSEL) | 0x06;
    UBRRL = 0x2F;          //set baud rate lo
    UBRRH = 0x00;          //set baud rate hi
    UCSRB = 0xF8;       // before D8
    //UCSRB |= (1<<RXEN); /* enable RX interrupt */

    // UCSRB &= ~(1<<RXEN); /* disable RX interrupt */

    UART_RxTail = 0;
    UART_RxHead = 0;
    UART_TxTail = 0;
    UART_TxHead = 0;
    RS_485_RCV_ON();
    Tx_Active_Flag = 0;
    Rec_Count=0;
    Rec_Lines=0;
    }


    #pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
    void uart0_rx_isr(void) //uart has received a character in UDR
    {
         unsigned char data;
        unsigned char tmphead;
     

         if (!Tx_Active_Flag && !(UCSRA & 0x10) )   // .
        {
           
           Rec_Count++;
           data = UDR; /* read the received data */
        /* calculate buffer index */
           tmphead = ( UART_RxHead + 1 ) & UART_RX_BUFFER_MASK;
           UART_RxHead = tmphead; /* store new index */
           if ( tmphead == UART_RxTail )
           {
              ;/* ERROR! Receive buffer overflow */
           }
           UART_RxBuf[tmphead] = data; /* store received data in buffer */
           if (data == 0x0D)
                 Rec_Lines++;
        }
        else
           data = UDR; /* read the received data */
    }

    #pragma interrupt_handler uart0_udre_isr:iv_USART0_UDRE
    void uart0_udre_isr(void)
    {
    //character transferred to shift register so UDR is now empty
         unsigned char tmptail;

        /* check if all data is transmitted */
        if ( UART_TxHead != UART_TxTail )
        {
                 if (!Tx_Active_Flag)  //
                {
                   Tx_Active_Flag = 1;
                      UCSRB &= ~(1<<RXEN); /* disable RX interrupt */
                   RS_485_SND_ON();
                      Wait(5);
                }
                                    /* calculate buffer index */
                tmptail = ( UART_TxTail + 1 ) & UART_TX_BUFFER_MASK;
                UART_TxTail = tmptail; /* store new index */
                UDR = UART_TxBuf[tmptail]; /* start transmition */
        }
        else
        {
            UCSRB &= ~(1<<UDRIE); /* disable UDRE interrupt */
        }
    }
    #pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC
    void uart0_tx_isr(void)
    {
        if ( UART_TxHead == UART_TxTail )
        {
              Wait(5);
            RS_485_RCV_ON();
            Tx_Active_Flag=0;
            UCSRB |= (1<<RXEN); /* enable RX interrupt */
        }
    }
     
    Это все работает на даче с 2007г, и не разу не трогал, не ресетил..
     
    DetSimen и ИгорьК нравится это.
  13. SergeiL

    SergeiL Оракул Модератор

    Все в мире относительно. Тайм, в реале, бывает разный :).
    И у кого-то, 1 секунда - RT, а у кого-то 1 миллисекунда - не RT.
    Все зависит от скорости процессов, и скорости реакции оборудования, управляющего процессом.
     
    Последнее редактирование: 11 июл 2019
  14. parovoZZ

    parovoZZ Гуру

    Но ведь выньдовс никто не называет RTOS просто потому, что она не является таковой.
     
  15. SergeiL

    SergeiL Оракул Модератор

    A если с RTX?
     
  16. Onkel

    Onkel Гуру

    Нет, ардуино перехватывает прерывания по завершению передачи, пихает в буфер следующий байт и опять включается в работу. Передачу на 9600 можно считать "фоновой" - одно прерывание (примерно) в миллисекунду на 10 тактов. Это вообще ничего
     
  17. Igor68

    Igor68 Гуру

    Да делайте Вы как Вам нравится! Вы же не переключаете контекст(кому надо работать, а кому ждать) допустим по таймеру или некому событию. Тут ребята сказали, что им достаточно событий по прерываниям, где и так идёт переключение стека и т.п. хоть и упрощенно. Они же "размазали" всё по прерываниям... и у них всё в работе. Да и я то же обхожусь на ARM7 без кернела, а уж задачи потолще будут.
     
  18. Onkel

    Onkel Гуру

    Работа без кернела- норм и в 8-битниках. У меня в кернеле обычно только шедулер и сброс вач дога.
     
  19. parovoZZ

    parovoZZ Гуру

    кернел - ти шо? Травка?
     
  20. Igor68

    Igor68 Гуру

    А что не так?
    - Повесил на прерывание FIQ (ARM7) от таймера 1 запись значения PWM из массива задания и чтение ADC в массив измерений
    - Повесил на прерывание IRQ (ARM7) от таймера 0 вывод в дисплей и опрос клавиатуры
    - Повесил на прерывание IRQ (ARM7) от таймера 2 коррекция задания в массиве PWM от массива ADC измерений (форма сигнала)
    - Повесил на прерывание IRQ (ARM7) от таймера 3 пересчёт и анализ предельных значений параметров и их соответствия
    - Основной цикл MAIN где анализ нажатой клавиши, соответствия заданию, реализация условий.
    А вот для IRQ, FIQ и USER разные стеки и наборы части регистров согласно архитектуре ядра. И зачем кернел в этом случае? Ведь время ВАЖНО!!!!!