Перейти к содержанию
    

Makki

Участник
  • Постов

    24
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о Makki

  • Звание
    Участник
    Участник
  1. Это я видел и понял. Я не хочу при выходе каждого нового процессора от ST писать новый стартап на си. А стартапы на си сам ST, похоже, не предоставляет (я правильно понял?). Конечно, если нет другого выхода, буду сам писать. Но если писать самому, всегда есть шанс ошибиться, с адресом, например. Поэтому хотелось завязаться на какой-то исходник от производителя. Опять же говорю, если стартапов на си от ST не существует, а подключать по условию .s не получится, буду сам ручками писать.
  2. Короче, ищу возможность подключать разные стандартные, не самописные!, а от производителя, стартапные файлы с таблицами векторов в зависимости от объявленного директивой #define типа микроконтроллера. Если это возможно. Более того, далее есть цель ещё и совместить в одном файле AVR и STM... Получить хочется что-то по принципу ардуино, такой типа простенький, но быстрый HAL для EWAVR и EWARM вместе взятых. Функционал, например: #define тип процессора, используемый усарт, его режим, далее просто в программе закидываем данные в стек и всё само работает. C avr такой принцип работает, но благодаря тому, что там все таблицы в .h файлах. С стм пока не получается.
  3. Ладно, пока попробую поискать у IAR или ST стартапы на C. Поищу в содержимом, например, по NMI_Handler() PS В папках иара пока что нет сишных. Все стартапы для STM .s PPS CubeMX тоже генерит проекты с использованием .s файлов
  4. Ну, может, неправильно добавляю... Всегда пользовался теми же #include Например, в EWAVR #ifdef USE_USART0 #ifdef DEBUG #define USART0_MODE_1W_AT #include "Serial_Osc_debug.c" #else #define USART0_MODE_1W_MODBUS #include "Modbus.с" #endif #include "AVR_usart.c" #endif Почему неправильно? Можно легче?
  5. Здравствуйте! Только начинаю работать с EWARM. STM32. Дошел до прерываний. Получилось запустить, работает, но файл с таблицей векторов startup_имя_процессора.s пришлось просто добавить в проект (не прописывая в файлах). Такой подход мне не понравился. Суть в чём, в EWAVR писал для себя файлики, в которых директивами препроцессора подключал нужные .h файлы с таблицами векторов для конкретного процессора. Возможно ли то же самое для ассемблерных .s стартап файлов для STM32? В лоб #include ... не получается - не знает компилятор ассемблера (или всё же знает?) - ошибки выдаёт. Подключать в каждом новом проекте ручками не хочется. Ну и хочется именно от иара или ст готовые использовать, то есть сам заново писать на си (читал, что так можно) пока не хочу. Ткните, пожалуйста, в какую сторону смотреть...
  6. Ага. Все понял, как только в раздел Type qualifiers заглянул. Спасибо за наводку! Пошел читать руководство...
  7. Всё, теперь мне все стало понятно. Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием... Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно. Получается что ли так: -если перед вызовом функции глобальной переменной присвоить значение, компилятор считает, что ее прерывание не изменит. -если значение не присваивать, компилятор считает, что переменная может быть изменена прерыванием. ?
  8. Как глобальная переменная (это видно по коду modbus_slave_routine()). unsigned char usart_count=0; А, я понял, к чему вы клоните. Тогда, похоже, компилятор даже не предполагает, что в modbus_slave_routine() между usart_count=0; и modbus_frame_check() переменная usart_count может быть изменена прерыванием. Но тогда при чем здесь Function inlining???
  9. Естественно об этом я тоже думал. Вот такой код: //Функция проверки кадра //Возвращает 0 если все ОК //#pragma inline=forced unsigned char modbus_frame_check(void) { //Ошибки физического уровня (в usart0_received) if((usart_flags&(1<<mberr))!=0){return 1;} //Длина кадра (не менее 4 символов) unsigned char num=usart_count; if(num<4){return 2;} //Контрольная сумма num-=2; //if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;} // return 0;//num; } Генерит то же самое: @00000096: modbus_slave_routine 285: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +00000096: B100 IN R16,0x00 In from I/O location +00000097: 700F ANDI R16,0x0F Logical AND with immediate +00000098: B900 OUT 0x00,R16 Out to I/O location 286: TCNT1H=0; +00000099: E000 LDI R16,0x00 Load immediate +0000009A: BD0D OUT 0x2D,R16 Out to I/O location 287: TCNT1L=0; +0000009B: BD0C OUT 0x2C,R16 Out to I/O location 288: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +0000009C: E008 LDI R16,0x08 Load immediate +0000009D: BD0E OUT 0x2E,R16 Out to I/O location 292: while((usart_flags&(1<<rxok))==0){;} +0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +0000009F: CFFE RJMP PC-0x0001 Relative jump 294: while((usart_flags&(1<<t15))==0){;} +000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000A1: CFFE RJMP PC-0x0001 Relative jump 296: if(modbus_frame_check()!=0){goto start;} +000000A2: B100 IN R16,0x00 In from I/O location +000000A3: CFF2 RJMP PC-0x000D Relative jump
  10. В общем-то вызываемая функция возвращает разные заначения, сейчас покажу. Так что думаю, не то это. Исходник: //Функция проверки кадра //Возвращает 0 если все ОК //#pragma inline=forced unsigned char modbus_frame_check(void) { //Ошибки физического уровня (в usart0_received) if((usart_flags&(1<<mberr))!=0){return 1;} //Длина кадра (не менее 4 символов) unsigned char num=usart_count; if(num<4){return 2;} //Контрольная сумма num-=2; //if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;} // return num; } /************************************************************/ //Обработчик ведомого Modbus (зациклен) void modbus_slave_routine(void) { start: //Сбрасываем таймер и всё-всё-всё и ждем приема ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); TCNT1H=0; TCNT1L=0; TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); usart_count=0; usart_SP=&usart_stack[0]; //Ждем первый символ while((usart_flags&(1<<rxok))==0){;} //Ждем окончания приема кадра while((usart_flags&(1<<t15))==0){;} //Проверяем посылку if(modbus_frame_check()!=0){goto start;} //Обрабатываем посылку и готовим ответ _delay_ms(20); } И то, что в дизассемблере с включенной Function inlining: @00000096: modbus_slave_routine 276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +00000096: B100 IN R16,0x00 In from I/O location +00000097: 700F ANDI R16,0x0F Logical AND with immediate +00000098: B900 OUT 0x00,R16 Out to I/O location 277: TCNT1H=0; +00000099: E000 LDI R16,0x00 Load immediate +0000009A: BD0D OUT 0x2D,R16 Out to I/O location 278: TCNT1L=0; +0000009B: BD0C OUT 0x2C,R16 Out to I/O location 279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +0000009C: E008 LDI R16,0x08 Load immediate +0000009D: BD0E OUT 0x2E,R16 Out to I/O location 283: while((usart_flags&(1<<rxok))==0){;} +0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +0000009F: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000A1: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +000000A2: B100 IN R16,0x00 In from I/O location +000000A3: CFF2 RJMP PC-0x000D Relative jump Как видно, modbus_frame_check() вообще не вызывается. И что характерно, даже нет попытки ее компилировать (если я правильно выражаюсь) - ее просто нет. А теперь отключаем оптимизацию Function inlining - функция появилась и работает: @000000AF: modbus_frame_check 259: if((usart_flags&(1<<mberr))!=0){return 1;} +000000AF: 9B03 SBIS 0x00,3 Skip if bit in I/O register set +000000B0: C002 RJMP PC+0x0003 Relative jump 259: if((usart_flags&(1<<mberr))!=0){return 1;} +000000B1: E001 LDI R16,0x01 Load immediate +000000B2: 9508 RET Subroutine return 261: unsigned char num=usart_count; +000000B3: 91000000 LDS R16,0x0000 Load direct from data space 262: if(num<4){return 2;} +000000B5: 3004 CPI R16,0x04 Compare with immediate +000000B6: F410 BRCC PC+0x03 Branch if carry cleared 262: if(num<4){return 2;} +000000B7: E002 LDI R16,0x02 Load immediate +000000B8: 9508 RET Subroutine return 267: return num; +000000B9: 5002 SUBI R16,0x02 Subtract immediate +000000BA: 9508 RET Subroutine return @000000BB: modbus_slave_routine 272: void modbus_slave_routine(void) 273: { +000000BB: E000 LDI R16,0x00 Load immediate +000000BC: E012 LDI R17,0x02 Load immediate +000000BD: 9300015A STS 0x015A,R16 Store direct to data space +000000BF: 9310015B STS 0x015B,R17 Store direct to data space 276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +000000C1: B100 IN R16,0x00 In from I/O location +000000C2: 700F ANDI R16,0x0F Logical AND with immediate +000000C3: B900 OUT 0x00,R16 Out to I/O location 277: TCNT1H=0; +000000C4: E000 LDI R16,0x00 Load immediate +000000C5: BD0D OUT 0x2D,R16 Out to I/O location 278: TCNT1L=0; +000000C6: BD0C OUT 0x2C,R16 Out to I/O location 279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +000000C7: E008 LDI R16,0x08 Load immediate +000000C8: BD0E OUT 0x2E,R16 Out to I/O location 280: usart_count=0; +000000C9: E000 LDI R16,0x00 Load immediate +000000CA: 9300015E STS 0x015E,R16 Store direct to data space 283: while((usart_flags&(1<<rxok))==0){;} +000000CC: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +000000CD: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +000000CE: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000CF: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +000000D0: DFDE RCALL PC-0x0021 Relative call subroutine +000000D1: 2300 TST R16 Test for Zero or Minus +000000D2: F771 BRNE PC-0x11 Branch if not equal 289: _delay_ms(20); +000000D3: E30F LDI R16,0x3F Load immediate +000000D4: E91C LDI R17,0x9C Load immediate +000000D5: 5001 SUBI R16,0x01 Subtract immediate +000000D6: 4010 SBCI R17,0x00 Subtract immediate with carry +000000D7: F7E9 BRNE PC-0x02 Branch if not equal +000000D8: C000 RJMP PC+0x0001 Relative jump +000000D9: 0000 NOP No operation 291: } +000000DA: 9508 RET Subroutine return Что характерно, если из вызывающей функции удалить обнуление таймера и счетчиков, все тоже работает, только вызываемая функция заинлайнена: @00000096: modbus_slave_routine 272: void modbus_slave_routine(void) 273: { +00000096: 9110015E LDS R17,0x015E Load direct from data space 283: while((usart_flags&(1<<rxok))==0){;} +00000098: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +00000099: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +0000009A: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +0000009B: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +0000009C: 9903 SBIC 0x00,3 Skip if bit in I/O register cleared +0000009D: CFFA RJMP PC-0x0005 Relative jump +0000009E: 2F01 MOV R16,R17 Copy register +0000009F: 3014 CPI R17,0x04 Compare with immediate +000000A0: F3B8 BRCS PC-0x08 Branch if carry set +000000A1: 5002 SUBI R16,0x02 Subtract immediate +000000A2: F7A9 BRNE PC-0x0A Branch if not equal 289: _delay_ms(20); +000000A3: E30F LDI R16,0x3F Load immediate +000000A4: E91C LDI R17,0x9C Load immediate +000000A5: 5001 SUBI R16,0x01 Subtract immediate +000000A6: 4010 SBCI R17,0x00 Subtract immediate with carry +000000A7: F7E9 BRNE PC-0x02 Branch if not equal +000000A8: C000 RJMP PC+0x0001 Relative jump +000000A9: 0000 NOP No operation 291: } +000000AA: 9508 RET Subroutine return Вот это для меня уже вообще непостижимо.
  11. Такая ситуация: имеем несколько вложенных друг в друга функций: main( level1 (level2 ())), полная оптимизация по скорости. При компиляции код функций уровня вложенности больше 2 просто исчезает (в дизассемблере смотрел), хоть просто возвращай переменную, хоть что угодно. Выполняется main( level1 ()) без вызова level2 () Убил часа 4 на поиск причины. Пока не добрался до function inlining. Отключил function inlining, все остальное так и оставил - помогло. Кто-нибудь знает, что это такое было??? И таки да, у меня Kickstart на 4 кб.
  12. __x The first pointer in the parameter list is placed in register X __z The first pointer in the parameter list is placed in register Z __x_z The first pointer in the parameter list is placed in register X and the second one in register Z __z_x The first pointer in the parameter list is placed in register Z and the second one in register X Почитал, попробовал, всё получилось, с одним маленьким исключением. Если в цикле функции, работающей с указателем ZH:ZL, есть вызов какой-либо другой функции, компилятор все равно сохраняет значение указателя во временные регистры. Поэтому для того, чтобы этого не было, все вызываемые функции пришлось "раскрыть". Странно, что компилятор не знает, что в вызываемых функциях ZH:ZL не изменяются... //Запись символьной строки __z void lcd_write_string(char __flash * string) { char i= * string++; while(i--!=0) { SetBit(lcdctrl,rs); __delay_cycles(3); SetBit(lcdctrl,e); lcddata=*string++; __delay_cycles(3); ClearBit(lcdctrl,e); ClearBit(lcdctrl,rs); __delay_cycles(4); ddrlcddata=0x00; lcddata=0x00; SetBit(lcdctrl,rw); SetBit(lcdctrl,e); while((lcddatain&(1<<db7))!=0) { ; } ClearBit(lcdctrl,e); ClearBit(lcdctrl,rw); lcddata=0x00; ddrlcddata=0xff; } } И, соответственно, результат компиляции. Тут всё работает так, как было бы написано мной на ассемблере, без оптимизации задержек, правда. @0000004C: lcd_write_string 48: char i= * string++; +0000004C: 9115 LPM R17,Z+ Load program memory and postincrement +0000004D: 2311 TST R17 Test for Zero or Minus +0000004E: F0D9 BREQ PC+0x1C Branch if equal +0000004F: 951A DEC R17 Decrement 53: SetBit(lcdctrl,rs); +00000050: 9A38 SBI 0x07,0 Set bit in I/O register 54: __delay_cycles(3); +00000051: C000 RJMP PC+0x0001 Relative jump +00000052: 0000 NOP No operation 55: SetBit(lcdctrl,e); +00000053: 9A3A SBI 0x07,2 Set bit in I/O register 56: lcddata=*string++; +00000054: 9105 LPM R16,Z+ Load program memory and postincrement +00000055: BB05 OUT 0x15,R16 Out to I/O location 57: __delay_cycles(3); +00000056: C000 RJMP PC+0x0001 Relative jump +00000057: 0000 NOP No operation 58: ClearBit(lcdctrl,e); +00000058: 983A CBI 0x07,2 Clear bit in I/O register 59: ClearBit(lcdctrl,rs); +00000059: 9838 CBI 0x07,0 Clear bit in I/O register 60: __delay_cycles(4); +0000005A: C000 RJMP PC+0x0001 Relative jump +0000005B: C000 RJMP PC+0x0001 Relative jump 61: DDRC=0x00; +0000005C: E000 LDI R16,0x00 Load immediate +0000005D: BB04 OUT 0x14,R16 Out to I/O location 62: lcddata=0x00; +0000005E: BB05 OUT 0x15,R16 Out to I/O location 63: SetBit(lcdctrl,rw); +0000005F: 9A39 SBI 0x07,1 Set bit in I/O register 64: SetBit(lcdctrl,e); +00000060: 9A3A SBI 0x07,2 Set bit in I/O register 65: while((lcddatain&(1<<db7))!=0) +00000061: 999F SBIC 0x13,7 Skip if bit in I/O register cleared +00000062: CFFE RJMP PC-0x0001 Relative jump 69: ClearBit(lcdctrl,e); +00000063: 983A CBI 0x07,2 Clear bit in I/O register 70: ClearBit(lcdctrl,rw); +00000064: 9839 CBI 0x07,1 Clear bit in I/O register 71: lcddata=0x00; +00000065: BB05 OUT 0x15,R16 Out to I/O location 72: DDRC=0xff; +00000066: EF0F SER R16 Set Register +00000067: BB04 OUT 0x14,R16 Out to I/O location +00000068: 2311 TST R17 Test for Zero or Minus +00000069: F729 BRNE PC-0x1A Branch if not equal 74: } +0000006A: 9508 RET Subroutine return
  13. Нашел настройку компилятора --lock regs, а потом использовал __no_init __regvar char __flash * pointer @ 14; но она позволяет жестко выделить только регистры с R4 по R15...
  14. Полная оптимизация по скорости добавила таки команду LPM R16,Z+, счетчик теперь хранится только в R26, но хранение указателя в регистрах R25:R24 осталось. Наверное, есть какой-нибудь способ, чтобы жестко привязаться к регистрам ZH:ZL, если это все же предусмотрено компилятором. Будем искать... @00000054: lcd_write_string 46: void lcd_write_string(char __flash * string) 47: { +00000054: 93AA ST -Y,R26 Store indirect and predecrement +00000055: 939A ST -Y,R25 Store indirect and predecrement +00000056: 938A ST -Y,R24 Store indirect and predecrement 48: char i= * string++; +00000057: 01F8 MOVW R30,R16 Copy register pair +00000058: 91A5 LPM R26,Z+ Load program memory and postincrement +00000059: 01CF MOVW R24,R30 Copy register pair +0000005A: 23AA TST R26 Test for Zero or Minus +0000005B: F039 BREQ PC+0x08 Branch if equal +0000005C: 95AA DEC R26 Decrement 51: lcd_write_character(*string++); +0000005D: 01FC MOVW R30,R24 Copy register pair +0000005E: 9105 LPM R16,Z+ Load program memory and postincrement +0000005F: 01CF MOVW R24,R30 Copy register pair +00000060: DFE7 RCALL PC-0x0018 Relative call subroutine +00000061: 23AA TST R26 Test for Zero or Minus +00000062: F7C9 BRNE PC-0x06 Branch if not equal 53: } +00000063: 9189 LD R24,Y+ Load indirect and postincrement +00000064: 9199 LD R25,Y+ Load indirect and postincrement +00000065: 91A9 LD R26,Y+ Load indirect and postincrement +00000066: 9508 RET Subroutine return А по поводу хранения строки - это у меня после написания протокола modbus привычка осталась - значение, например, порта ввода-вывода любым может быть, и конец посылки по символу определять некорректно.
  15. Доброго всем времени суток! С недавних пор начал разбираться с компилятором IAR, до этого писал на ассемблере. Начал простенький проектик с графическим дисплеем. Пытаюсь вывести на экран строку, расположенную в памяти программ. Строка, конечно, выводится, отображается как надо, но вот какими методами... В общем, есть у меня функция: void lcd_write_string(char __flash * string) { char i= * string++; while(i--!=0) { lcd_write_character(*string++); } } Принимает она указатель на flash, где переменная где у меня выглядит следующим образом: char __flash string[]={5,'A','B','C','D','E'}; 5 - число символов в строке, дальше символы. При компиляции всего этого начинаются для меня непонятные вещи: @00000057: lcd_write_string 46: void lcd_write_string(char __flash * string) 47: { +00000057: 940E00D2 CALL 0x000000D2 Call subroutine;тут компилятор сохраняет в программный стек регистры, хотя это и не нужно, ну да ладно +00000059: 01C8 MOVW R24,R16 Copy register pair;тут получили указатель, переданный через пару регистров R16:R17 48: char i= * string++; +0000005A: 01FC MOVW R30,R24 Copy register pair;но почему было сразу их не занести в ZH:ZL??? +0000005B: 91A4 LPM R26,Z Load program memory;если бы сразу занесли в ZH:ZL, можно бы было сделать LPM R26,Z+ +0000005C: 9601 ADIW R24,0x01 Add immediate to word;тогда эта строка лишняя +0000005D: C004 RJMP PC+0x0005 Relative jump;прыг +5 51: lcd_write_character(*string++); +0000005E: 01FC MOVW R30,R24 Copy register pair;опять переносим в Z указатель +0000005F: 9104 LPM R16,Z Load program memory +00000060: DFE9 RCALL PC-0x0016 Relative call subroutine;собственно, запись символа +00000061: 9601 ADIW R24,0x01 Add immediate to word;и почему-то увеличиваем указатель уже после выполнения функции 49: while(i--!=0) +00000062: 2F0A MOV R16,R26 Copy register;вот зачем дальше вся эта чехарда, когда можно просто проверить R26??? +00000063: 2FA0 MOV R26,R16 Copy register +00000064: 95AA DEC R26 Decrement +00000065: 2300 TST R16 Test for Zero or Minus +00000066: F7B9 BRNE PC-0x08 Branch if not equal;прыг на -8 53: } +00000067: E0E3 LDI R30,0x03 Load immediate +00000068: 940C00D6 JMP 0x000000D6 Jump Итак, вопрос: это такая работа компилятора, или это я чего-то не знаю? Как напрямую в регистр ZH:ZL скормить указатель и работать именно с этими регистрами? Нет, я могу то же самое написать на ассемблере, и ассемблерную библиотеку прикрутить, но зачем тогда мне компилятор?
×
×
  • Создать...