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

Плавный переход C -> C++ под МК

Так в любом случае код уровня Hardware не совместим между разными производителями микроконтроллеров. Где-то может быть и совпадение, но не везде будет всё одинаково, несмотря на одно и то же ядро Cortex.
И особенно вы ставите себе палки в колеса тем, что не используете битовые описания. То есть, когда #define SPI_CR1_SPE (1 << 0), позицию бита нужно поправить в одном месте. А когда в тексте вместо SPI_CR1_SPE везде стоит (1 << 0), изменить позицию бита очень непросто.
Вы стреляете себе в ногу. От таких ошибок предостерегали в книгах.

Ну и я уже писал - нужны абстракции уровней. Уровень Hardware меняете, а остальное - остается или подвергается значительно меньшим переделкам.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, EdgeAligned сказал:

Так в любом случае код уровня Hardware не совместим между разными производителями микроконтроллеров. Где-то может быть и совпадение, но не везде будет всё одинаково, несмотря на одно и то же ядро Cortex.
И особенно вы ставите себе палки в колеса тем, что не используете битовые описания. То есть, когда #define SPI_CR1_SPE (1 << 0), позицию бита нужно поправить в одном месте. А когда в тексте вместо SPI_CR1_SPE везде стоит (1 << 0), изменить позицию бита очень непросто.
Вы стреляете себе в ногу. От таких ошибок предостерегали в книгах.

Ды нет, думаю коллега выше просто пишет свои описания. Я как-то напоролся на то, что в двух разных МК одного производителя (STM32) биты с одним назначением лежали в разных позициях. Заметить такое при переносе своих самописных дефайнов практически не реально. А при использовании готовых поставляемых определений, об этом даже не придется задуматься, с 99.999% вероятностью.

STM32F0

image.png.5ed7b901bc4ec068a19745e328dfa631.png


STM32F4

image.png.72818f3510e17cb5d7ae053a3fdfdcc3.png

 

Подстава, которой не ждали. И такого вполне себе хватает, чтобы на ровном месте застрять в отладке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

49 минут назад, EdgeAligned сказал:

Тяжело в ученье, не спорю. Я тоже вот многократно перечитываю, пока изучаю. На одном мониторе открыта IDE, на другом мониторе - пдф-ка мануала. Еще и 12-дюймовый планшетник использую, чтобы не крутить во все стороны. Ну а че поделать, приходится.

У меня в универе был одногруппник. Он на все экзамены писал шпоры на все билеты. Полностью. Целую кипу шпор. А потом сам их не использовал - раздавал. Когда его спрашивал: "На кой так делаешь, раз сам почти не пользуешь?" Он говорил: "Пока их пишу, я их выучиваю и потом уже помню, даже без шпор".

Так и тут - пока пишу описания регистров, я их функционал запоминаю.

49 минут назад, EdgeAligned сказал:

странный подход, странный. А как вы пишите? Магические цифры? Тоесть, не SPI_CR1_SPE, а (1 << 0)? прикольно конечно, экстравагантно.

Вот например кусок SPI-драйвера:

    case F_TRA:
      spiC->TRBSCR = B0 | B14;
      if (!(n = faz.tra.dlast)) {
        if (i & 1 << SO_ER) {
          faza = i += F_TRA_STOP - F_TRA << SO_n;
          PingMain();
        } else EndTra();
        return;
      }
      if (n >= BURST_SPI_R * 2) {
        IntDis(concat(NVIC_USIC, USIC_UNIT(nUSIC_spi), _, SRUSIC_SR(nUSIC_SR_spi_RX)));
        AtomicOrI(&DLR.LNEN, 1 << nDMALINE_spi_RX);
        spiC->RBCTR_b[1] = BURST_SPI_R * 2 - 1 - 1;
        __DMB();
        rdmaU->CHEN = (1 << (nDMALINE_spi_RX & 7)) * (B0 | B8);
      } else {
        spiC->RBCTR_b[1] = USIC_FIFO_SIZE;
        __DMB();
      }
      tdmaU->CHEN = (1 << (nDMALINE_spi_TX & 7)) * (B0 | B8);

spiC и tdmaU - это соответственно USIC (последовательный порт) и DMA-unit (контроллер). Как видно - все битовые поля заданы численно.

49 минут назад, EdgeAligned сказал:

Но именно от такого подхода предостерегают многие именитые программисты в своих книгах, которые мне доводилось читать.

Что там пишут диванные эксперды, никогда не занимавшиеся реальными проектами - мне совершенно по-барабану.

А вот если бы они реально что-то писали сами (а не таскали кубиками из чужих проектов), то как бы им помогло описание битов регистров?

Вот читаем описание битов одного из регистров SPI:

/*USICx_C0_PCR_SSC*/          
/*USICx_C1_PCR_SSC*/          
struct {                      
__REG32 MSLSEN            : 1;
__REG32 SELCTR            : 1;
__REG32 SELINV            : 1;
__REG32 FEM               : 1;
__REG32 CTQSEL1           : 2;
__REG32 PCTQ1             : 2;
__REG32 DCTQ1             : 5;
__REG32 PARIEN            : 1;
__REG32 MSLSIEN           : 1;
__REG32 DX2TIEN           : 1;
__REG32 SELO              : 8;
__REG32 TIWEN             : 1;
__REG32                   : 6;
__REG32 MCLK              : 1;
} ssc;

И видите вы в коде что-то типа:

spiC->SSC = 1 << SELCTR | 2 << CTQSEL1 | 1 << DX2TIEN;

Т.е. - ранее вы сами написали это, но потом, через год нужно что-то изменить. Вы это читаете.... Вы сразу понимаете что означают эти SELCTR, CTQSEL1, DX2TIEN? Вот так сразу, не заглядывая в мануал сможете сказать, что означают эти значения записываемые в эти биты? Если нет - зачем тогда давать им эти символьные имена?

Или всё-таки придётся открывать мануал? А в мануале ведь эти биты описаны по порядку - по номерам битов. И искать их там удобнее по номерам битов, чем по этим зубодробительным именам. И это ещё я короткие имена привел. А загляните например в EthernetMAC:

/* ETH0_MMC_Receive_Interrupt_Mask */
typedef struct {
  __REG32 RXGBFRMIM           : 1;
  __REG32 RXGBOCTIM           : 1;
  __REG32 RXGOCTIM            : 1;
  __REG32 RXBCGFIM            : 1;
  __REG32 RXMCGFIM            : 1;
  __REG32 RXCRCERFIM          : 1;
  __REG32 RXALGNERFIM         : 1;
  __REG32 RXRUNTFIM           : 1;
  __REG32 RXJABERFIM          : 1;
  __REG32 RXUSIZEGFIM         : 1;
  __REG32 RXOSIZEGFIM         : 1;
  __REG32 RX64OCTGBFIM        : 1;
  __REG32 RX65T127OCTGBFIM    : 1;
  __REG32 RX128T255OCTGBFIM   : 1;
  __REG32 RX256T511OCTGBFIM   : 1;
  __REG32 RX512T1023OCTGBFIM  : 1;
  __REG32 RX1024TMAXOCTGBFIM  : 1;
  __REG32 RXUCGFIM            : 1;
  __REG32 RXLENERFIM          : 1;
  __REG32 RXORANGEFIM         : 1;
  __REG32 RXPAUSFIM           : 1;
  __REG32 RXFOVFIM            : 1;
  __REG32 RXVLANGBFIM         : 1;
  __REG32 RXWDOGFIM           : 1;
  __REG32 RXRCVERRFIM         : 1;
  __REG32 RXCTRLFIM           : 1;
  __REG32                     : 6;
} __eth_mmc_receive_interrupt_mask_bits;

Это один из регистров MAC. Как вам такие имена???:wacko:

Искать описание по номеру позиции бита гораздо удобнее и быстрее, чем искать что-то типа "RX512T1023OCTGBFIM".

 

PS: Когда-то по-дурости, наслушавшись подобных "экспердов" переписал некоторые драйвера с использованием именованных позиций бит. Потом, когда пришлось через некоторое время что-то там переделывать, долго плевался. Понял - насколько удобнее с числовыми номерами битов.

Когда пишу, что-то связанное с периферией, у меня всегда открыт мануал на неё. И искать в нём гораздо удобнее по номерам битов. А у некоторых производителей ещё и имена битов в мануале отличаются от имён, заданных в хидерах. Тут вообще задница была бы.  :unknw:

45 минут назад, Arlleex сказал:

Касательно другой периферии: да, я подсматриваю в референс. А как без этого? Никак. Разве что если это уже было когда-то написано, а сейчас надо перетянуть в другой проект, поправив максимум какой-нибудь DMA-канал или лапы МК.

Вот! И эти выводы вы делаете по простой периферии STM32. А теперь возьмём например XMC4700, в котором регистров и битов в них - кратно больше. Там вам придётся всё время держать мануал перед глазами.

45 минут назад, Arlleex сказал:

Почему?:shok:

Выше написал уже.

45 минут назад, Arlleex сказал:

При разработке CMSIS-заголовков авторы не лепили описание всего и вся в один хедер. Описание регистров разделено, поэтому описание регистров ядра МК берется из файла, который не поставляется вендором МК. Он един для всех МК на этом ядре.

В тех исходниках, что я видел (от 3D-принтера) всё было свалено в одну кучу. И там была куча перекрёстных ссылок. И кусков хидеров, в которых идут ссылки на всё и вся. И выдирание любого описания периферии (даже не используемой) приводило к несборке всего проекта. Так просто там взять и заменить описание периферии ядра на своё никак не получалось.

36 минут назад, EdgeAligned сказал:

И особенно вы ставите себе палки в колеса тем, что не используете битовые описания. То есть, когда #define SPI_CR1_SPE (1 << 0), позицию бита нужно поправить в одном месте. А когда в тексте вместо SPI_CR1_SPE везде стоит (1 << 0), изменить позицию бита очень непросто.

А какой смысл её менять??? Вы думаете этот бит дрейфует по регистру?  :biggrin:

36 минут назад, EdgeAligned сказал:

Вы стреляете себе в ногу. От таких ошибок предостерегали в книгах.

В чём именно "стреляю"? Ничего не понял.... уже лет 20 как программирую разные МК и ноги мои почему-то до сих пор целые.  :unknw:

36 минут назад, EdgeAligned сказал:

Ну и я уже писал - нужны абстракции уровней. Уровень Hardware меняете, а остальное - остается или подвергается значительно меньшим переделкам.

Вижу - начитались вы диванных экспердов.... Которые никогда ничего сложнее абдуриновского кода не видели.... :biggrin:

Все эти биты в регистрах периферии - это как раз и есть тот самый нижний "hardware"-уровень. Который меняется полностью при переходе на другой МК. Вместо с этими битами. Поэтому это никак не мешает абстракции. Абстракция - она не на уровне битов должна быть. А выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Видимо, вы не знакомы с принятыми в CMSIS правилами именования и оформления 🙂 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, jcxz сказал:

spiC->SSC = 1 << SELCTR | 2 << CTQSEL1 | 1 << DX2TIEN;

Т.е. - ранее вы сами написали это, но потом, через год нужно что-то изменить. Вы это читаете.... Вы сразу понимаете что означают эти SELCTR, CTQSEL1, DX2TIEN? Вот так сразу, не заглядывая в мануал сможете сказать, что означают эти значения записываемые в эти биты? Если нет - зачем тогда давать им эти символьные имена?

Мозг штука интересная, конечно, все он не запоминает. Но имена битов (дефайны), такие же как в мануале, запомнить проще, нежели непонятные номера битов-ноунэймов вида B0, B10, и т.д. И часто бывает как раз так, что имя бита не требует заглядывания в мануал. Я понятия не имею и даже через час не вспомнил бы, что значит

spiC->TRBSCR = B0 | B14;

Я не понимаю, как это для Вас нагляднее, например, этого

USART2->CR1 = USART_CR1_OVER8 |
              USART_CR1_TE    |
              USART_CR1_RE;


Все-таки, даже спустя большое количество времени мозг, глядя на эти биты TE, RE, не подсвечивает их "не знакомыми" - с большой вероятностью программист вспомнит, что это Transmitter Enable и Receiver Enable. Но когда там будет написано

USART2->CR1 = B3 | B2;

Вы тут же полезете в мануал, т.к. даже пару минут спустя уже забудете, что эти биты значат.

Да, не все биты по их имени отражают, что они делают. Но многие. А у вас - ноль.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 минут назад, jcxz сказал:

Вижу - начитались вы диванных экспердов....

Ого! Прикольно! Впервые встречаю человека, отвергающего концепцию уровней абстракции, которая была сформулирована еще на заре программирования вообще, в прошлом тысячелении.
Вы наверно прямо из main() дергаете биты в регистрах. Мдяяя. пичалька, пичалька. Не знаю, является ли для вас "диванным экспертом" автор языка Си, но то, что вы изобрели "альтернативную концепцию" - это точно 🙂 Однако, боюсь, что ваша концепция мало кому из мэтров программирования подходит. Они то как раз наоборот, стоят за идеей отделения мух от котлет.

Читайте ПРАВИЛЬНЫЕ книги.

 

 

11 минут назад, Forger сказал:

шутка юмора в тему:

хахаха! 🙂 прочитал.
Да, я путал TX и RX, и не только регистры, но и провода. Дома есть три паяльника, от старого советсткого 65-ваттного до паяльной станции. Ардуину хоть не пробовал, но просматривал ихние скетчи и даже лазил по ихнему форуму ради прикола. Чето даже отвечал там, поржав. Правда, забанили, ибо "шипко умный и дерзкий". Полярность питания путал, сжег дисплей и несколько микроконтроллеров. Но не работал в НИИ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, Arlleex сказал:

И часто бывает как раз так, что имя бита не требует заглядывания в мануал. Я понятия не имею и даже через час не вспомнил бы, что значит

spiC->TRBSCR = B0 | B14;

Я не понимаю, как это для Вас нагляднее, например, этого

USART2->CR1 = USART_CR1_OVER8 |
              USART_CR1_TE    |
              USART_CR1_RE;

Вы всё время сравниваете с простой периферией STM32. В которой всего 5 регистров в UART и несколько бит. И где легко запомнить функции бит и ассоциировать их с названиями. А попробуйте как-нить поработать на сложном МК. Типа XMC. Где в том же UART битов - раз в десять больше. И, так как их функционал очень богатый, то и функции очень заковыристые. А потом расскажите - что вам скажут названия: 1 << SELCTR | 2 << CTQSEL1 | 1 << DX2TIEN через неделю хотя-бы?

Сможете? Если битов этих не десяток, а штук 100?

Я же уже писал: "уже пробовал давать символьные имена битам" - потом всё пришлось переделывать. Так как с номерами - гораздо быстрее и понятнее разобраться.

Вот для справки типичный начальный инит SPI+DMA для внешней флешки на XMC4700:

void InitDflash()
{
  static TPinSel const tPinmux[] = {
    PINSEL_I(PIN_DF_MISO, PINSEL_USIC(nUSIC_df, DATA), STRONG_SOFT, PU),
    PINSEL_O(PIN_DF_MOSI, PINSEL_USIC(nUSIC_df, DOUT0), PINSEL_USIC(nUSIC_df, DATA), STRONG_SOFT),
    PINSEL_O(PIN_DF_SCLK, PINSEL_USIC(nUSIC_df, SCLKOUT), NONE, STRONG_SHARP, SET1),
    PINSEL_O(PIN_DF_CS0, PINSEL_USIC_SELO(nUSIC_df, PIN_DF_CS0), NONE, STRONG_SOFT, SET1),
    PINSEL_O(PIN_DF_CS1, PINSEL_USIC_SELO(nUSIC_df, PIN_DF_CS1), NONE, STRONG_SOFT, SET1)
  };
  int i = DFLASH_CHIP_N - 1;
  do {
    chipStat[i] = CHIP_ERASE;
    chipWait[i] = 0;
  } while (--i >= 0);
  i = ncell(ops) - 1;
  do {
    ops[i].cmd = Op::OP_NOP;
    OsSemCreate1(&ops[i].sem);
  } while (--i >= 0);
  PeripheralOn(concat(SCU_PERIPH_USIC, USIC_UNIT(nUSIC_df)));
  spiC->KSCFG = B0 | B1 | B7 | B11;
  { int dummy = spiC->KSCFG; }
  if (~spiC->CCFG & (B0 | B6 | B7)) trap(TRAP_DFLASH | ERR_UNEMPLEMENTED << 16);
  spiC->CCR = 0;
  spiC->DXCR[0] = USIC_DXn(PIN_DF_MISO, nUSIC_df, 0) | B4;
  spiC->DXCR[3] = B4;
  spiC->FDR = B10 - 1 | 1 << 14;  //Normal divider mode selected, FD_CLK = PBCLK
  spiC->BRG = T_LD_TD - 1 << 10 | DFLASH_PBCLK_DIV - 1 << 16 | 1 << 30;
  spiC->SCTR = B0 | B1 | 1 << 8 | 63 << 16 | 7 << 24;
  spiC->TCSR = B0 | B8 | 1 << 10;
  spiC->PCR = B0 | B1 | B2 | B3 | 2 << 4 | F2F_SPLIT - 1 << 8;
  spiC->RBCTR = spiC->TBCTR = 0;
  spiC->TRBSCR = B0 | B1 | B2 | B8 | B9 | B10 | B14 | B15;
  spiC->INPR = SRUSIC_SR(nUSIC_SR_df_ERR) * (B0 | B4 | B8 | B12 | B16);
  spiC->TBCTR = USIC_CH(nUSIC_df) * USIC_FIFO_SIZE * 2 | 1 << 8 |
    SRUSIC_SR(nUSIC_SR_df_TX) << 16 | SRUSIC_SR(nUSIC_SR_df_ERR) << 19 |
    concat(USIC_FIFO_SIZE_, USIC_FIFO_SIZE) << 24 | B30 | B31;
  spiC->RBCTR = USIC_CH(nUSIC_df) * USIC_FIFO_SIZE * 2 + USIC_FIFO_SIZE |
    SRUSIC_SR(nUSIC_SR_df_RX) << 16 | SRUSIC_SR(nUSIC_SR_df_ERR) << 19 |
    concat(USIC_FIFO_SIZE_, USIC_FIFO_SIZE) << 24 | B28 | B30 | B31;
  spiC->PSCR = -1;
  spiC->CCR = 1 | B11;
  DMAon(1 << nDMALINE_df_TX | 1 << nDMALINE_df_RX);
  rdmaC->SAR = (u32)&spiC->OUTR;
  rdmaC->CFG[0] = DMAPRI_SPI_RX << 5 | B10;
  rdmaC->CFG[1] = B1 | 1 << 2 | (nDMALINE_df_RX & 7) << 7;
  tdmaC->CFG[0] = DMAPRI_SPI_TX << 5 | B11;
  tdmaC->CFG[1] = B0 | B1 | 1 << 2 | (nDMALINE_df_TX & 7) << 11;
  AtomicOrI(&DLR.LNEN, 1 << nDMALINE_df_TX);
  PinSelN(tPinmux);
}

Теперь заменяем все численные позиции битов на символьные. Этот исходник распухает раз так в ~5. И заполняется всякими:

scr001.thumb.png.23d2e537cfc2d035d53373f1304b93b8.png

Сможете через неделю вспомнить назначение всех этих RBERIEN, SRBIEN, ARBIEN, ...  ?

Всё равно придётся лезть в мануал и смотреть. А там смотреть удобнее по номерам битов. И строки хоть в ширину экрана влазят - исходник компактнее, значит в нём ориентироваться проще.

2 минуты назад, Arlleex сказал:

Все-таки, даже спустя большое количество времени мозг, глядя на эти биты TE, RE, не подсвечивает их "не знакомыми" - с большой вероятностью программист вспомнит, что это Transmitter Enable и Receiver Enable.

В случае простых контроллеров с простой периферией - да, наверное. Но не в случае сложной периферии. Просто попробуйте сами на практике. Потом будете говорить.

2 минуты назад, Arlleex сказал:

Да, не все биты по их имени отражают, что они делают. Но многие. А у вас - ноль.

Мне и не нужно отражать. Пока  я пишу драйвер - я их помню. А потом всё равно нужно лезть в мануал. А ориентироваться в более коротком коде - намного проще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, ну мы уже поняли про ваш "путь джедая". Спасибо, нам понятно. Это нам (лично мне, и наверняка многим другим) НЕ ПОДХОДИТ. СПАСИБО! Спасибо, достаточно.

Ну нет, правда, спасибо, но вот это:

 spiC->TRBSCR = B0 | B1 | B2 | B8 | B9 | B10 | B14 | B15;

не подходит. Спасибо, не стоит ЭТО предлагать.

это один из самых ужасных кодов, которые мне приходилось видеть. Честно. На мой личный взгляд.
Если вам нравится - пользуйтесь, никто не запрещает. Всё дело в привычке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

29 минут назад, EdgeAligned сказал:

Ого! Прикольно! Впервые встречаю человека, отвергающего концепцию уровней абстракции, которая была сформулирована еще на заре программирования вообще, в прошлом тысячелении.

С чего вы взяли??? Где я её отвергал?  Я писал, что вы со своими интернетными гуру не понимаете, что такое "абстракция" и где её нужно делать. И делается она не на уровнях битов регистров.

Есть такая поговорка: "Слышал звон, да не знаю где он". Вот это как раз о вашем понимании абстрагирования.

29 минут назад, EdgeAligned сказал:

Однако, боюсь, что ваша концепция мало кому из мэтров программирования подходит. Они то как раз наоборот, стоят за идеей отделения мух от котлет.

Боюсь, что вы даже десятой части того объёма кода и коммерческих проектов не сделали, что я. А значит - значимость вашего мнения о моей концепции - на уровне погрешности округления.  :biggrin:

Концепция моя построена на собственном многолетнем практическом опыте, а не на мнении диванных экспердов, вчера только узнавших, что "ARM" - это не всегда рука.  :sarcastic:

И изделия мои работают по всему миру миллионами экземпляров уже много лет.

14 минут назад, EdgeAligned сказал:

не подходит. Спасибо, не стоит ЭТО предлагать.

это один из самых ужасных кодов, которые мне приходилось видеть. Честно. На мой личный взгляд.

Вот когда вы сможете создать что-то своё, стоящее. И это будет работать. И будет продаваться и пользоваться людьми, вот тогда ваше мнение будет иметь хоть какое-то значение.

Ну или - покажите нам как правильно? Сможете?... :wink:

 

Этот код по дорогам ездит. Сейчас прямо. И не один год. А скоро будет и по ветрякам лазить. А ваш?  :unknw:

Аналогичные коды работают вполне возможно и в вашем городе - рядом, считают электроэнергию по всей РФ, управляют насосами на северах, общаются со спутниками, диагностируют пациентов в клиниках и т.п. А что делают ваши? Или ваших экспертов из инетика?  :sarcastic:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, jcxz сказал:

не понимаете, что такое "абстракция" и где её нужно делать. И делается она не на уровнях битов регистров.

хорошо. На уровне чего она делается? Научите нас, о великий программист! С удовольствием послушаем. (поржем конечно потом, но послушаем) 🙂 чего только не наслушаешься в этих ваших интернетах. 🙂 чисто из любопытства.

 

3 минуты назад, jcxz сказал:

Концепция моя построена на собственном многолетнем

...заблуждении 🙂 Да, "не все йогурты одинаково полезны"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, EdgeAligned сказал:

хорошо. На уровне чего она делается? Научите нас, о великий программист! С удовольствием послушаем. (поржем конечно

Сперва вы - пример "правильного" кода SPI-драйвера флешки для XMC4700 - в студию!

Я ведь первый спросил. Ждём, готовим попкорн.

 

PS: Хотя к чему это спрашивать? Сразу же видно что вы - диванный теоретик.  :biggrin::biggrin::biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 минут назад, jcxz сказал:

В случае простых контроллеров с простой периферией - да, наверное. Но не в случае сложной периферии. Просто попробуйте сами на практике. Потом будете говорить.

Есть контроллеры и посложнее XMC. Чего уж - линукс поддерживает зоопарк процессоров с разными архитектурами и окружением, и под них люди тоже пишут драйвера. Залез вот в дебри какого-то исходника - и что я вижу... задефайненные имена битов.

https://github.com/rockchip-linux/kernel/blob/9ed2be4b9c001ca8006cb4c72928c09927c44f89/drivers/net/ethernet/nxp/lpc_eth.c#L632

А они (кто там пилит линукс) тоже кода пишут километры в день. Такая себе метрика, на самом деле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 минут назад, jcxz сказал:

Сперва вы - пример "правильного" кода SPI-драйвера флешки для XMC4700 - в студию!

С XMC4700 не работаю, нет в нем нужды. Но на примере STM32, пожалста (в сокращенном виде, разумеется):

HAL:

static void Write(uint16_t data)
	{
		constexpr SPI_TypeDef *spi = getBase();
		while(!(spi->SR & SPI_SR_TXE));
		spi->DR = data;
	}

BSP на примере дисплея

template<typename SPI, typename CS, typename DC>
class ST75256 {
public:
static bool PowerOn(bool on)
	{
  		if(SPI::IsBusy()) return false;
		CS::Low();
		DC::Low();
		SPI::Write(0x95 & ~on);
		WaitComplete();
		CS::High();
  		return true;
	}

Не претендую на прям стопудовую правильность в деталях, но в общем и целом, считаю это правильно. Потому что оно работает, и хорошо работает. И если нужно будет пересесть на какой-нить XMC, то заменить здесь нужно будет то, что написано внутри HAL, и это, я считаю, правильно. Уровень BSP остается практически неизменным, за исключением возможной разницы в структуре микроконтроллера в целом. Голова программисту на то и дана, чтобы гибко подстраиваться под изменчивый мир железок.

И еще до перехода на ++ писал в аналогичном стиле. Так то я тоже ведь порядка 20 лет в эмбедде. Еще ПИКи на асме прогал жеж.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

33 минуты назад, Arlleex сказал:

Есть контроллеры и посложнее XMC. Чего уж - линукс поддерживает зоопарк процессоров с разными архитектурами и окружением, и под них люди тоже пишут драйвера. Залез вот в дебри какого-то исходника - и что я вижу... задефайненные имена битов.

Ок. а теперь расскажите мне, как с "задефайненными именами" сделать то, что я могу у себя?

Например есть описание распределения event-ов и ног для таймера:

#define PIN_MLX1          1,  1  //Sch signal "TiredPWM_1", Melexis IR sensor input, used for measure rotor temperature (PWM coded)
#define PIN_MLX2          3,  15 //Sch signal "TiredPWM_2", Melexis IR sensor input, used for measure rotor temperature (PWM coded)

#define nCCU_mlx1         40, 2  //захват ШИМ-сигнала 1-го ИК-термометра MLX90614
#define nCCU_mlx2         42, 0  //захват ШИМ-сигнала 2-го ИК-термометра MLX90614

enum { //распределение номеров event-ов в nCCU_mlx1 и nCCU_mlx2
  EVENT_MLX_start = 0,  //event используемый для синхронного старта
  EVENT_MLX_rise = 1,   //event используемый для сигнала захвата таймера по фронту PIN_MLX1 и PIN_MLX2
  EVENT_MLX_fall = 2    //event используемый для сигнала захвата таймера по спаду PIN_MLX1 и PIN_MLX2
};

Макросы поддержки связывания:

//преобразование индекса входной линии CCU в её буквенное обозначение
#define CCU_LETTER_IN(letter)   concat(CCU_MUX_LETTER_, letter)
//номер выхода CCU для данного CCU/slice на данном порту/пине
#define CCU_SLICE_OUT4(unit, slice, port, pin) concat(PINMUXO_P, port, _, pin, _CCU, unit, _SLICE, slice)
#define CCU_SLICE_OUT(nCCU_slice, port_pin)    CCU_SLICE_OUT4(nCCU_slice, port_pin)
//номер(буква) входа CCU для данного CCU/slice на данном порту/пине
#define CCU_PIN_IN4(unit, slice, port, pin)  CCU_LETTER_IN(concat(CCU, unit, _IN, slice, _PIN, port, _, pin))
#define CCU_PIN_IN(nCCU_slice, port_pin)     CCU_PIN_IN4(nCCU_slice, port_pin)

И далее я пишу в регистр, привязывающий эти event-ы к событиям в таймере:

  CCU_MLX1_S.INS =
    CCU_GSC_IN(nCCU_mlx1) << EVENT_MLX_start * 4 |
    1 << EVENT_MLX_start * 2 + 16 |
    CCU_PIN_IN(nCCU_mlx1, PIN_MLX1) << EVENT_MLX_rise * 4 |
    1 << EVENT_MLX_rise * 2 + 16 |
    3 << EVENT_MLX_rise * 2 + 25 |
    CCU_PIN_IN(nCCU_mlx1, PIN_MLX1) << EVENT_MLX_fall * 4 |
    2 << EVENT_MLX_fall * 2 + 16 |
    3 << EVENT_MLX_fall * 2 + 25;
  CCU_MLX2_S.INS =
    CCU_GSC_IN(nCCU_mlx2) << EVENT_MLX_start * 4 |
    1 << EVENT_MLX_start * 2 + 16 |
    CCU_PIN_IN(nCCU_mlx2, PIN_MLX2) << EVENT_MLX_rise * 4 |
    1 << EVENT_MLX_rise * 2 + 16 |
    3 << EVENT_MLX_rise * 2 + 25 |
    CCU_PIN_IN(nCCU_mlx2, PIN_MLX2) << EVENT_MLX_fall * 4 |
    2 << EVENT_MLX_fall * 2 + 16 |
    3 << EVENT_MLX_fall * 2 + 25;
  CCU_MLX2_S.CMC = CCU_MLX1_S.CMC = EVENT_MLX_start + 1 | EVENT_MLX_rise + 1 << 4 | EVENT_MLX_fall + 1 << 6;

Это простой пример. И я тут могу быстро поменять список event-ов. Как то же самое сделать с символьными именами?

Есть гораздо более сложные связи. Там, где номера каких-то периферийных узлов (номера пинов, номера service request-ов внутри чипа, номера DMA-каналов и DMA-запросов) используются для вычисления позиций битов. Иногда - по весьма сложным формулам. И такое - почти везде. 

И это даёт мне возможность быстро поменять номера пинов, к которым привязана какая-то периферийная функция, поменять распределение service request-ов или DMA-каналов при переезде на новую плату или простой доработке схемы. Практически не трогая код драйвера.

Вышеприведённый код драйвера SPI-флешь у меня работает на разных XMC4xxx в разных проектах. Практически без изменений! А вот ноги, номера SPI, номера прерываний и прочих цепей  - разные. Я просто меняю соответствующие номера в bsp.h и всё - код переезжает на новую плату.

Покажите - как это сделать без вычисляемых битовых позиций. Можно конечно наворотить макросов. Но это будет намного сложнее. И только с одной целью - побороть невозможность прямого вычисления битовых позиций. А тогда - нафига они сдались эти символьные имена битов???

33 минуты назад, Arlleex сказал:

Есть контроллеры и посложнее XMC.

Посложнее по периферии??? Вот уж не уверен. Работал некогда с OMAP-L137. 4-ядерном. На котором линух тоже бегает. Так скажу вам - по многой периферии XMC4xxx даст ему 100 очков вперёд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...