kan35
Участник-
Постов
643 -
Зарегистрирован
-
Посещение
-
Победитель дней
1
Весь контент kan35
-
Приведение типов в Си
kan35 ответил kan35 тема в Программирование
а разве знаковое число не двоично дополненное, 0x88 это же -120 то есть если даже знак продублируется, то должно получиться 0xFF78, но выходит 0xFF88... Получаются довольно смешные конструкции: ... = ((unsigned short)((unsigned char)x)) << 1; это если я хочу привести к 16 битному виду и сдвинуть на 1 разряд. То есть два раза подряд привожу тип, это же не должно быть так... -
Приведение типов в Си
kan35 опубликовал тема в Программирование
Доброго всем дня! наткнулся на неожиданное поведение компилятора MCC18 (для PIC18), по нему значится как "ANSI '89 compatibility" Привожу тип и получаю разные результаты в зависимости...: signed char x = 0x88; unsigned short y = x; // y=0xFF88 unsigned short y = (unsigned short)x; // y=0xFF88 unsigned short y = (unsigned char)x; // y=0x0088 Ранее этот же кусочек кода работал в GCC/ARM, IAR AVR и всегда было unsigned short y = x; // y=0x0088 Я как человек старой закалки понимаю, что нужно было явно приводить тип, и даже самым надежным будет приведение через указатель в память, типа такого: unsigned short y = *(unsigned short *)&x; // y=0x0088 Но все таки, даже если делать просто приведение по умолчанию как y=x - что за результат-то такой 0xFF88? И почему приведение (unsigned char) делает как мне нужно, а (unsigned short) - опять странное 0xFF88. Это какая то особенность старого ANSI '89? как будто не логично это... -
Похоже я нашел таки проблему! И она в недостаточно подробной справке к порту или точнее недоисследованности ситуации с математикой. Да, я посмотрел в карте памяти MATH_DATA udata 0x000000 data 0x000010 .tmpdata udata 0x000010 data 0x00000c В моем случае сумма не 19 байт, а 28. И я как честный человек поменял portCOMPILER_MANAGED_MEMORY_SIZE с 19 на 28. И решил я поискать где этот макрос используется, обнаружил- что нигде кроме резервирования памяти и вот полез я в port.c. /* Store the .tempdata and MATH_DATA areas as described above. */ \ CLRF FSR0L, 0 \ CLRF FSR0H, 0 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF INDF0, PREINC1 \ MOVFF FSR0L, PREINC1 \ MOVFF FSR0H, PREINC1 \ Не разумею я этот птичий язык, но понимаю, что MOVFF POSTINC0, PREINC1 делается 19 раз, соответсвенно делалось и на Restore. Поэтому, добавил еще 9 строк MOVFF POSTINC0, PREINC1 и 9 строк соответственно в MOVFF POSTDEC1, POSTDEC0 И таким образом я наконец то, я надеюсь, что сохраняю и восстанавливаю математический контекст как надо! Надеюсь, ком нибудь будет полезно.
-
Да, режим джедая это конечно хорошо, но все таки хотелось бы победить его, а не как сейчас - он победил меня. Вот, например мои утилиты работы со строками в карте памяти: .udata_string_my.o udata 0x000dae data 0x000000 .idata_string_my.o idata 0x000dae data 0x000000 то есть не занимают память вне стека. И вот так выглядит функция, которая "ошибается" при сравнении строк (если без критических секций): unsigned char strings_strcmpram2pgm (const char * str_pgm, rom const char * str_ram) { unsigned int ptr = 0; STRINGS_ENTER_CRITICAL(); while (str_pgm[ptr] == str_ram[ptr] && str_ram[ptr] != 0) { ptr++; } if (ptr && str_pgm[ptr] == str_ram[ptr] && str_ram[ptr] == 0) { STRINGS_EXIT_CRITICAL(); return 0; } STRINGS_EXIT_CRITICAL(); return 1; } (другие функции тоже ошибаются если что). В общем - что тут криминального, чего ему не хватает то - просто даже любопытно.
-
Доброго дня всем! Еще один не понятный момент. Указано в справке к порту для PIC18 https://www.freertos.org/a00097.html что код компилятора C18 не реентрантный, в частности по 32 битной математике, и это отдельно решается, ок. В то же время я обнаружил, что стандартные функции типа strtsr, strcpy, memcpy и т д - тоже глючат если их в разных потоках вызывать, что значит, что они тоже не реентратные. Попробовал написать свои функции для работы со строками, и оказалось, что они получаются тоже не реентрантные, в итоге все их заключаю в критические секции и все работает нормально. Конечно использовать критические секции по этому поводу не хотелось бы, так как это потребует снижать скорости по последовательным портам, и накладывать прочие ограничения. Может быть кто сталкивался с такой вот проблемой нереентранности на PIC18 и C18 и есть какие-нибудь изящные решения...
-
string_received это глобальный массив к сожалению и действительно, строки можно было бы передавать индексом в таком случае, но я решил сделать указателем. Это как раз на случай если массив в какой то момент сделаю динамическим.
-
Именно, передаются указатели, я же так и написал в самом первом сообщении. Queue - это инструмент, который мне удобен, я передаю сигнал о готовности строки и другая задача просыпается и сразу получает указатель на эту строку. Обертка в данном случае это наиболее изящное решение, спасибо!
-
Расползание темы в разные дебри не связанные с вопросом я всегда одобряю, так как это однозначно лучше молчания! Спасибо всем гуру. Не знаю, как так уже вышло, но я всегда объявлял массивы строк как char string_received[2][64]; В данном случае при обращении к строкам они лежат друг за другом в памяти, сперва string_received[0], потом string_received[1], каждая по 64.
-
Не надо меня подозревать, пожалуйста 🙂 Мне так нужно и я так использую. Действительно на низкой оптимизации такое поведение меня не смутило бы. У меня оптимизация - максимальная.
-
Вопрос, наверное, стоит закрыть. И данная псевдопроблема не имеет красивого решения, так как если бы в памяти выделилось место под указатель, то в принципе я бы эту память и потерял после этого. Придется иметь некий массив из временных указателей, спасибо разработчикам mcc18, если кому то интересно про эту фичу пиков почитать - вот здесь обсуждение, например https://forum.microchip.com/s/topic/a5C3l000000M2v4EAC/t241282 А, кстати, есть еще один компилятор от Микрочипа - XC8, может быть кто знает - есть ли в природе порт FreeRTOS под него? Может он попрямее будет, если уж его взяли на смену mcc18.
-
Принимающая сторона ждет не char **, а char * 🙂 По сути - адрес строки в ОЗУ. xQueueTCPRxedString = xQueueCreate( 2, sizeof( char *) ); И да, при приеме из очереди мы сами назначаем тип: unsigned char * str_rcv; if (xQueueReceive(xQueueTCPRxedString, &str_rcv, 5000) == pdTRUE) { Спасибо за оправку в учебники, я, действительно, не эксперт по Си, поэтому и обращаюсь в благородным гуру! Мое мнение такое, что должна возникнуть переменная, в которой будет содержаться адрес строки. И потом эту переменную скормить в QueueSend, после чего переменная может и исчезнуть (и хорошо, если бы исчезла), это уже без разницы, так как её контент уже в queue. И как я уже сообщил ранее, если вручную её создать, то оно и работает, вопросов с этим нет. Но в силу того, что компилятор довольно кривой, он не чистит стек, если переменная не используется далее, то есть все временные переменные остаються в стеке. В итоге стек засоряется так быстро, что не успеваешь моргнуть, поэтому стараюсь писать чище. Кстати, стек под одну функцию в pic18 что то около 100 байт 🙂, в mcc18 к сожалению это не обходится, хотя я не понимаю, почему так они сделали. Компилятор даже такую ошибку выдает - "Стек заполнен"- такие дела... В общем, как мне видится, запись должна быть что-то в виде такого: xQueueSend(xQueueTCPRxedString, &((char *)string_received[0]), 0); Но компилятор не пропускает это, "Syntax error". Логично, что если делать как я ранее делал xQueueSend(xQueueTCPRxedString, string_received[0], 0); то в Queue попадает первые два байта строки, что в общем не то, то нужно. Кстати, если делать как jcxz предложил: xQueueSend(xQueueTCPRxedString, &string_received[0][0], 0); то в Quue попадают те же первые два байта строки, не?😎 Передавать в Queue &string_received[0][0] или string_received[0] или &string_received[0] - это всё одно и то же, но я проверил на всякий случай)) В общем, есть ощущение, что без промежуточной переменной не обойтись, как ни крути. Первый раз такое в Си мне встретилось, ранее считал, что все, что можно при желании можно уложить в одну строку кода.
-
Доброго дня всем! Столкнулся с такой проблемой, надо передать строку через Queue. Скорее вопрос по Си, но все таки для FreeRTOS. Есть массив из строк: char string_received[2][64]; Я хочу передать указатель или на string_received[0] или на string_received[1]. Соотвественно, я делаю так: char * data; data = string_received[0]; xQueueSend(xQueueTCPRxedString, &data, 0); И это работает, все хорошо. А как бы мне не заводя новую переменную передать указатель? xQueueSend(xQueueTCPRxedString, &string_received[0], 0); - так не пойдет, а как правильно? PS: я бы может и не заморачивался сделать одной строкой, но как только я создаю переменную char * data, то я навсегда теряю память в стеке, то есть она не удалится после того, как она перестанет быть нужна, такой дурацкий компилятор у меня (mcc18 если что 🙂).
-
О, спасибо, поймал байт!!! я про этот регистр и не знал, кстати на TX это не влияет почему-то. Всем огромнейшее спасибо за помощь, два дня потерял на поиски (думал, что в SPP что-то не так делаю), прежде чем спросить, и уже собирался перепаивать мк.
-
Пока для упрощения я просто пытаюсь поймать хотя бы срабатывание. Вообще, изначально я прерывание сделал. Но оно не работало, и начал разбираться что происходит и такой простейший код написал. RX и TX тоже пробовал замыкать (модем выключал) - тоже ничего.
-
Написал комментарии к инициализационному коду, чтобы выглядело опрятнее: unsigned short ulBaud; unsigned char dummy_byte; /* Calculate the baud rate generator constant. SPBRG = ( (FOSC / Desired Baud Rate) / 4 ) - 1 */ ulBaud = (unsigned short)(48000000l / ulWantedBaud); ulBaud /= ( unsigned short ) 4; ulBaud -= ( unsigned short ) 1; // IO pins setup TRISAbits.TRISA3 = 1; // RX as input TRISAbits.TRISA2 = 0; // TX as output // baudrate init BAUDCON1 = 0; // reset unwanted bits BAUDCON1bits.BRG16 = 1; // 16 bit BRR BAUDCON1bits.RXDTP = 0; // normal polarity for direct shifter switch SPBRG1 = ulBaud; // BR low byte SPBRGH1 = ulBaud>>8; // BR high byte // SPP-Lite setup //RPINR0_1 &= 0xF0; // write 0 to [3:0], RP3 to USART1_RX RPINR0_1bits.U1RXR = 0; //RPOR2_3 = (RPOR2_3&0xF0)|0x01; // RP2 to USART1_TX RPOR2_3bits.RPO2R = 0x1; // TX serup TXSTA1 = 0; // reset unwanted bits TXSTA1bits.TX9 = 0; // 9th bit disable TXSTA1bits.TXEN = 1; // transmitter enable TXSTA1bits.SYNC = 0; // anync mode TXSTA1bits.BRGH = 1; // high baud rate enable //RC setup RCSTA1 = 0; // reset unwanted bits RCSTA1bits.SPEN = 1; // UART enable RCSTA1bits.RX9 = 0; // 9th bit disable RCSTA1bits.CREN = 1; //continues receive mode // Interrupt setup // IPR1bits.RC1IP = 0; //serLOW_PRIORITY; // PIE1bits.RC1IE = 1; // IPR1bits.TX1IP = 0; //serLOW_PRIORITY; // PIE1bits.TX1IE = 1; Ошибки я тоже тестирую: while(1) { uart_send_string(line_at); //uart_send_data(line_at, 4); vTaskDelay(100); if (PIR1bits.RC1IF) { while(1) { Blink(); vTaskDelay(500); } } if (RCSTA1bits.FERR || RCSTA1bits.OERR) { while(1) { Blink(); vTaskDelay(50); } } } В этом цикле постоянно отправляется AT\r\n, в ответ модем сыпет ОК. Обе линии я проверяю виртуальным компортом и в терратерме вижу это всё хорошо. То есть такое ощущение складывается, как будто в UART вообще ничего не залетает. Еще, я не уточнил ранее подключение, модем подключен к линиям RA3 - прием, RA2 - передача в модем.
-
Уважаемые коллеги, столкнулся с такой простой задачей и в силу того, что я новичок - не могу понять в чем проблема. К порту USART1 подключен модем. Передавать данные получилось довольно легко, а вот с приемом - никак. Настроил скорость - 115200, выдаю AT\r, в ответ летит ОК\r. И вот тут дальше - ни в какую. Инизиализиру так: TRISAbits.TRISA3 = 1; // RX as input RPINR0_1 &= 0xF0; // write 0 to [3:0], RP3 to USART1_RX RCSTA1 = 0; // reset unwanted bits RCSTA1bits.SPEN = 1; RCSTA1bits.RX9 = 0; RCSTA1bits.CREN = 1; Далее в цикле передачи проверяб флаг заполнености буфера приемника if (PIR1bits.RC1IF) {//И никогда сюда не попадаю. Анализатором на ножке данные вижу, они точно там есть и с ними все в порядке. Но флаг не взводится. Такое подозрение, что я неправильно как то сконфигурировал SPP_Lite на вход. Или что то не доделал, а что?.. С примерами в интернете довольно сложно по этому чипу... Заранее спасибо за подсказки!
-
Driver_GV, Многократное спасибо за помощь и подсказки! Соответсвенно, я выбрал Legacy и скачал. Этот: правильно же? Или лучше старее брать? Действительно, нашел проект под USB-CDC VCP под PIC18F67J94. Открыл его в среде MPLAB-IDE 8.95. Однако ж он с ходу не собрался, к сожалению, воюю дальше. За ваш пример так же огромное спасибо. Но там нет файла проекта, а я пока без него не могу 🙂 Придется вручную собирать, чтобы попробовать
-
Доброго дня всем. Нужен совет! Pадача у меня самая простая - сделать утилиту для конфигурирования устройства. Но столкнулся, что под этот камень конкретно не так много примеров и тем более с USB. В этой связи вопрос - USB на семействе PIC18 везде одинаковый? И у меня еще ограничение - компилятор MCC18 (так как часть приложения уже писана под него). В общем, порекомендуйте стек CDC/VCP, который не будет сложно портировать под PIC18F67J94. С уважением, Александр
-
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Update Оказалось, что опция "Enable Multi-bank stack model" Должна быть активна. То есть порт с сайта FreeRTOS.org вполне тоже рабочий. Только вот в нем не хватает файла-проекта под MPLAB X. Поисследовав файл проекта под MPLAB IDE нашел конфигурационную строку TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}=-w3 -DMPLAB_PIC18F_PORT -Ls -Opa- -nw 2074 -nw 2066 И здесь опция -Ls как раз про это. Мне надо было внимательнее это прошерстить с самого начала, сэкономил бы день. Кстати, может ли меня кто-нибудь ткнуть носом - что эта опция дает? Я почему то думал, что она включает по-банковый доступ к памяти, а получается наоборот - банки объединает в один массив? или как? Я смотрел в документации Микрочипа, но там тоже нет объяснения для меня. -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Ну в общем, можно сказать победа. Наладил кое-как. Хотя до конца не понял что именно сделал, что оно заработало, сейчас буду искать что... Все таки работает НЕ в extended mode. В extended постоянно сваливается в ресет когда в первый раз восстанавливает контекст. Проект прикрепил, правда на старой версии FreeRTOS пока. Может быть кому то это будет полезно когда-нибудь. Если налажу современный официальный порт, я его выложу тоже. gitprj.X_good.zip -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Да, задачу поставил и не отступлю. С вашей помощью, конечно:-) Во FReeRTOS стеки под задачи выделяются из общей кучи. То есть 2кБ - 7*100 = 1.3кБ свободного места в куче. + обычный стек - 256 байт, и остается еще 1кБ свободного. Тут не так все плохо. Все таки оказалось, что прерывания срабатывают,однако происходит как я понимаю сброс контроллера при restore_context, тут что-то у меня с памятью. Даже вряд ли из за extended mode. Подскажите, как правильно его сконфигурировать, чтобы ОЗУ предсталов линейном виде? Я в опциях компилятора только вижу. При чем в обычном режиме выгоядит иначе, чем в extended. Обычный extended А в коде ничего нужно активировать? Или во фьюзах? -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Там стек каждой по сто байт, всего куча операционки - 2кб. Я согласен, что ресурсы ограничены, но у меня будет 5-7 задач, поэтому я в этом принципиально не сомневаюсь. Решил попробовать откомпилировать в extented mode, почему то в прерывание таймера не запрыгивает в таком варианте, почему такое может быть? Почему так пробую - в примерах c гита он включен. На сколько это может быть принципиально? -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Я все таки настроен на FreeRTOS, а порты доступны только для C18, поэтому на нем. Принял решение оставаться на MPLAB X. Опробовал официальный порт с сайна FreeRTOS, а так же старый пример с гитхаба (https://github.com/sybreon/freertos-pic18). И оба раза столкнулся со странной одинаковой проблемой. Во первых пришлось немного подкрутить настройку таймера 1, чтобы запустился системный таймер. static void prvSetupTimerInterrupt( void ) { const unsigned long ulConstCompareValue = ( ( configCPU_CLOCK_HZ / portTIMER_FOSC_SCALE ) / configTICK_RATE_HZ ); unsigned long ulCompareValue; unsigned char ucByte; /* Interrupts are disabled when this function is called. Setup CCP1 to provide the tick interrupt using a compare match on timer 1. Clear the time count then setup timer. */ TMR1H = ( unsigned char ) 0x00; TMR1L = ( unsigned char ) 0x00; /* Set the compare match value. */ ulCompareValue = ulConstCompareValue; CCPR1L = ( unsigned char ) ( ulCompareValue & ( unsigned long ) 0xff ); ulCompareValue >>= ( unsigned long ) 8; CCPR1H = ( unsigned char ) ( ulCompareValue & ( unsigned long ) 0xff ); CCP1CONbits.CCP1M0 = portBIT_SET; /*< Compare match mode. */ CCP1CONbits.CCP1M1 = portBIT_SET; /*< Compare match mode. */ CCP1CONbits.CCP1M2 = portBIT_CLEAR; /*< Compare match mode. */ CCP1CONbits.CCP1M3 = portBIT_SET; /*< Compare match mode. */ PIE3bits.CCP1IE = portBIT_SET; /*< Interrupt enable. */ /* We are only going to use the global interrupt bit, so set the peripheral bit to true. */ INTCONbits.GIEL = portBIT_SET; /* Provided library function for setting up the timer that will produce the tick. */ //OpenTimer1( T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T12_CCP1_T34_CCP2345 ); // timer 1 setup // Timerx clock source is the system clock (FOSC) T1CONbits.TMR1CS1 = portBIT_CLEAR; T1CONbits.TMR1CS0 = portBIT_CLEAR; // no prescaler (1:1) T1CONbits.T1CKPS1 = portBIT_CLEAR; T1CONbits.T1CKPS0 = portBIT_CLEAR; // Do not synchronize external clock input T1CONbits.NOT_T1SYNC = portBIT_SET; // 16 bit T1CONbits.RD16 = portBIT_CLEAR; // enable timer T1CONbits.TMR1ON = portBIT_SET; // init done signal LATG = 0b10; } Вроде все нормально, сделал выдачу клока на пин, и получил четкий сигнал 500Гц (1кГц системной частоты). Потом сделал две задачи для мигания каждая своим портом. #pragma config XINST=OFF #pragma config FOSC=PRIPLL #pragma config CLKOEN=OFF #pragma config IESO=ON #pragma config PLLDIV=PLL4X #pragma config POSCMD=HS static void vTask1(void *pvParameters) { while (1) { taskENTER_CRITICAL(); LATE ^= 0b01; taskEXIT_CRITICAL(); //vTaskDelay(1000); } } static void vTask2(void *pvParameters) { while (1) { taskENTER_CRITICAL(); LATE ^= 0b10; taskEXIT_CRITICAL(); //vTaskDelay(1000); } } /* * */ void main(void) { /* Power up Configuration*/ TRISE = 0xF0; TRISG = 0xFC; LATE = 0; LATG = 0; /* Create tasks */ xTaskCreate(vTask1, "T1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(vTask2, "T2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); /* Start the scheduler. Will never return here. */ vTaskStartScheduler(); return; } И тут должно было мне прийти счастье, но нет. Я получаю такую картинку: Дело в том, что на порту емкостная нагрузка, потому последовательность такая: 1мс вверху, потом 1мс генерация 300+кГц, потом 1мс внизу и так далее. На обоих задачах одно и то же. Как только раскомментирую vTaskDelay в задачах - перестает выдавать что-либо. Есть видимость, что многозадачность как то и работает, но что происходит не понятно - как будто задачи работают с нестабильной скоростью или как то так... задержки не работают совсем. Что может такое быть!? При чем как уже упомянут оба доступных примера работают одинаково. Моего кода в них практически нет. Что я упускаю? Приложил проект, может быть кому то будет любопытно взглянуть на это безобразие с виду простое. Всем спасибо за подсказки и помощь! gitprj.X.zip -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Я так понимаю, что в основном отладчиком никто не пользуется, тем более, что он требует особой сборки кода, что, конечно не может не настораживать. Да, не идеально работает на Pickit-3. В таком раскладе, действительно, есть смысл работать на MPLAB X, и отлаживаться строкам, тем более, что найти ICD2 в наше непростое время вряд-ли удастся. Вы написали про бутлодер- имеете в виду свой собственный бутлодер? или у микрочипа есть контроллеры с такими специальными бутлодерами с USB и т д? -
PIC18 MPLAB проблема с компилятором?
kan35 ответил kan35 тема в Cредства разработки для МК
Установил 8.95. Действительно, симулятор на mcc заработал, это уже классно. А на какой версии будет работать дебагер?:-) Или ни на какой? update вообще то - отладка работает. Хоть и не без глюков. Например ставишь точку останова - запускаешь и оно крутится пока паузу не нажмешь и вот ты стоишь на точке останова. По шагам ходит. Все это в принципе уже радует!