Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Сб янв 06, 2024 20:12:46

TEPEM писал(а):Есть три неприятные функции в хале, которые я пытаюсь заменить cmsis.

Если я правильно понял, ТС используется SPI для работы с W25Qxxx. Вот простейший вариант реализации доступа к этой микросхеме. Работает на STM32F4.
Спойлер
Код:
#define W25Q_GUARD  ( 40'000'000 )

////////////////////////////////////////////////////////////////////////////////

uint8
W25Q::SPI_exchange( uint8 _aByte )
{
    uint8
        tmp8;
    int32
        guard = W25Q_GUARD;

    while( ( spi -> SR & SPI_SR_RXNE ) && ( guard > 0 ) )
    {
        tmp8 = spi -> DR;
        guard--;
    };

    if( guard <= 0 )
    {
        theMemoryIsBad = true;

        #ifdef DEBUG
            log_printf
            (
                MsgCat::ERR,
                "FTP : W25Q : Memory is bad. Line %d.\n", __LINE__
            );
        #endif

        return( 0 );
    }

    *( volatile uint8 *)&( spi -> DR) = _aByte;

    guard = W25Q_GUARD;

    while( ( !( spi -> SR & SPI_SR_RXNE ) ) && ( guard > 0 ) )
    {
        guard--;
    }

    if( guard <= 0 )
    {
        theMemoryIsBad = true;

        #ifdef DEBUG
            log_printf
            (
                MsgCat::ERR,
                "FTP : W25Q : Memory is bad. Line %d.\n", __LINE__
            );
        #endif

        return( 0 );
    }

    tmp8 = *( volatile uint8*)&( spi -> DR );

    return( tmp8 );
}

////////////////////////////////////////////////////////////////////////////////

uint8
W25Q::SPI_readByte( void )
{
    if( theMemoryIsBad == true )
    {
        return( 0 );
    }

    return( SPI_exchange( 0 ) );
}

////////////////////////////////////////////////////////////////////////////////

uint16
W25Q::SPI_readBytes( uint8* _buff, uint16 _n )
{
    if( theMemoryIsBad == true )
    {
        return( 0 );
    }

    if( ( _buff == 0 ) || ( _n == 0 ) )
    {
        return( 0 );
    }

    uint16
        i = _n;

    while( i )
    {
        *_buff = SPI_readByte();
        _buff++;
        i--;

        if( isFault() )
        {
            return( 0 );
        }
    }

    return( _n );
}

////////////////////////////////////////////////////////////////////////////////

void
W25Q::SPI_writeByte( uint8 _aByte )
{
    if( theMemoryIsBad == true )
    {
        return;
    }

    SPI_exchange( _aByte );
}

////////////////////////////////////////////////////////////////////////////////

uint16
W25Q::SPI_writeBytes( uint8* _buff, uint16 _n )
{
    if( theMemoryIsBad == true )
    {
        return( 0 );
    }

    if( ( _buff == 0 ) || ( _n == 0 ) )
    {
        return( 0 );
    }

    uint16
        i = _n;

    while( i )
    {
         SPI_writeByte( *_buff );
        _buff++;
        i--;

        if( isFault() )
        {
            return( 0 );
        }
    }

    return( _n );
}

////////////////////////////////////////////////////////////////////////////////

bool
W25Q::isFault( void )
{
    return( theMemoryIsBad );
}

////////////////////////////////////////////////////////////////////////////////

На всякий случай настройка SPI под эту микруху.
Спойлер
Код:
...
    spi -> CR1 =
        ( 0  << SPI_CR1_BIDIMODE_Pos )  | // 15
        ( 0  << SPI_CR1_BIDIOE_Pos )    | // 14
        ( 0  << SPI_CR1_CRCEN_Pos )     | // 13
        ( 0  << SPI_CR1_CRCNEXT_Pos )   | // 12
        ( 0  << SPI_CR1_DFF_Pos )       | // 11
        ( 0  << SPI_CR1_RXONLY_Pos )    | // 10 Fullduplex
        ( 1  << SPI_CR1_SSM_Pos )       | //  9  Software slave management disabled
        ( 1  << SPI_CR1_SSI_Pos )       | //  8
        ( 0  << SPI_CR1_LSBFIRST_Pos )  | //  7 MSB передается первым
        ( 0  << SPI_CR1_SPE_Pos )       | //  6 Пока _не_ включаем SPI!
        ( br << SPI_CR1_BR_Pos )        | //  5..3 делитель шины для тактирования SPI;
        ( 1  << SPI_CR1_MSTR_Pos )      | //  2 Master
        ( 0  << SPI_CR1_CPOL_Pos )      | //  1 полярность тактового сигнала
        ( 0  << SPI_CR1_CPHA_Pos );       //  0 Фаза тактового сигнала

    spi -> CR2 = \
        ( 0 << SPI_CR2_TXEIE_Pos )      | // Tx buffer empty interrupt enable
        ( 0 << SPI_CR2_RXNEIE_Pos )     | // RX buffer not empty interrupt enable

        // This bit controls the generation of an interrupt when an error
        // condition occurs )(CRCERR, OVR, MODF in SPI mode, FRE in TI mode and
        // UDR, OVR, and FRE in I2S mode).
        ( 0 << SPI_CR2_ERRIE_Pos )      |
        ( 0 << SPI_CR2_FRF_Pos )        | // 0/1 - Motorola/TO mode
        ( 0 << SPI_CR2_SSOE_Pos )       | // SS output enable
        ( 0 << SPI_CR2_TXDMAEN_Pos )    | // Tx buffer DMA enable
        ( 0 << SPI_CR2_RXDMAEN_Pos );     // Rx buffer DMA enable

        spi -> CR1 |= ( 1  << SPI_CR1_SPE_Pos );
...

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Сб янв 06, 2024 21:01:04

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

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Пт янв 19, 2024 06:33:51

_

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Пт янв 19, 2024 09:31:22

Стандартный путь пойти на сайт производителя и посмотреть схему чем не устраивает?

Обычные линейные стабилизаторы это. А в каком месте маркировка не английском там? :)

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Ср янв 24, 2024 12:49:48

Владислав! Вся надежда на Вас как обычно) И снова здравствуйте)
TIM2_CH2 дает шим на hcpl3120 та на транзистор и тот на двигатель.
Вот такой код
Код:
 GPIOB->MODER |=  GPIO_MODER_MODER3_1;     
       GPIOB->PUPDR |=   GPIO_PUPDR_PUPD3_1;
       GPIOB->AFR[0] |= 0x00001000;//PB3 AF1 - TIM2_CH2 
       
        TIM2->CR1       |= TIM_CR1_ARPE; // buffer the ARR register (not esp useful in this example)               
        TIM2->PSC       = 96000000/1000000-1; // scale to 1us
        const int freq  = 800; // Hz
        TIM2->ARR       = 1000000/freq; // convert freq to counts. Auto Reload Register
        TIM2->CCR2      = TIM2->ARR/10; // Duty cycle 50% on Compare/Capture Register 2
        TIM2->CCMR1     |= TIM_CCMR1_OC2PE // Enable preload for channel 2
                        | (0b110 << TIM_CCMR1_OC2M_Pos); // PWM mode 1                   
        TIM2->CCER      |= TIM_CCER_CC2E; // Enable Capture Compare for channel 2
        TIM2->EGR       |= TIM_EGR_UG;

Кнопочка там делает TIM2->CR1 |= TIM_CR1_CEN; и все работает.
Но есть одно огромное НО. Запуск при подаче питания на плату, с порта вылетает +3в. ИБП не расчитан на прямое включение, оффает сразу от такого подката. Да и фиг бы с ним. Но и движку крутится не надо без кнопки. Ни какие танцы с бубном вокруг подтяжки порта не чего не дают. Более того только выключение 2го канала таймера избавляет от этого плевка в начале, но стоит его включиить и шим начинается с этого плевка. Я уже хз что делать хоть дополнительный ключ ставить в схему управления драйвером. Выручайте пж

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Ср янв 24, 2024 15:11:26

Берём отладчик в руки и останавливаемся на команде включения таймера. Непосредственно сразу перед её выполнением смотрим состояние всех регистров. Выход CH2 это функция от значения этих регистров. Тыкаем в отладчике значения и смотрим какой бит влияет на неправильное поведение.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Вс янв 28, 2024 15:52:52

так там и должна быть "1", исходно CNT < CCR =ARR/10. чего не так?

"110: PWM mode 1 (режим 1 ШИМ) - при счете вверх канал 1 активен (OC1REF=1), пока TIMx_CNT < TIMx_CCR1, иначе не активен (OC1REF=0). "

при включении TIM2->CCER |= TIM_CCER_CC2E;
состояние OCxREF отображается на ногу.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Сб фев 03, 2024 00:34:16

Просто сделал програмный шим.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Вт фев 06, 2024 23:35:28

Правильно, долой всю аппаратную периферию... :))) :facepalm:

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 20:22:26

Здравствуйте! Подключаю дисплей ST7735 к 32L476. SPI1. Использую проверенную инициализацию. И он вроде запускается, рябь все дела. А залить не заливается.
Единственное что поменял кроме пинов - переключение 8 / 16 битовой передачи. Ибо до этого юзал 411 стм. Там было SPI2->CR1 &= ~SPI_CR1_DFF;
А в 476 нет DEF и вместо него я юзаю SPI1->CR1 &= ~SPI_CR1_CRCL;
Вроде синониумы. Еще грешу на пины дисплея TP0 & TP1 они у меня в воздухе. Подскажите пж, давно сношаюс
вот код инициализации и заливки
Спойлер
Код:
void Send_CMD(uint8_t dat)
{
        CS_LOY;  //ChipSelect loy
   DC_LOY;  //DC LoyLevel        
   SPI1->CR1 &= ~SPI_CR1_CRCL;   
   while (!(SPI1->SR & SPI_SR_TXE));
   SPI1->DR = dat;
   while (!(SPI1->SR & SPI_SR_TXE));
   while ((SPI1->SR & SPI_SR_BSY));
        CS_H;  //ChipSelect Up
       
}
void Send_DAT(uint8_t dat){
        CS_LOY;  //ChipSelect loy
   DC_H;  //DC H         
   SPI1->CR1 &= ~SPI_CR1_CRCL;      
   while (!(SPI1->SR & SPI_SR_TXE));
   SPI1->DR = dat;
   while (!(SPI1->SR & SPI_SR_TXE));
   while ((SPI1->SR & SPI_SR_BSY));   
         CS_H;//ChipSelect Up
}

void Send_DAT16(uint16_t dat){
        CS_LOY;  //ChipSelect loy
   DC_H;  //DC H      
   SPI1->CR1 |= SPI_CR1_CRCL;      
   while (!(SPI1->SR & SPI_SR_TXE)){};
   SPI1->DR = dat;
   while (!(SPI1->SR & SPI_SR_TXE)){};
   while ((SPI1->SR & SPI_SR_BSY)){};
         CS_H;//ChipSelect Up
}

void LCD_Init()
{
 CS_LOY;  //ChipSelect loy
        SPI1->CR1 |= SPI_CR1_SPE;//On Spi1
         RST_H;  //RST Hay
        Delay(5);
    RST_LOY;  //RST loy
   Delay(15);
        RST_H;  //RST Hay
   Delay(15);
        Send_CMD(0x01);//Sbros nastroek
        Delay(35);
       
    Send_CMD(ST77XX_SWRESET);
    Delay(150);
    Send_CMD(ST77XX_SLPOUT);
    Delay(500);

    Send_CMD(ST7735_FRMCTR1);
    Send_DAT(0x01);
    Send_DAT(0x2C);
    Send_DAT(0x2D);
 
    Send_CMD(ST7735_FRMCTR2);
    Send_DAT(0x01);
    Send_DAT(0x2C);
    Send_DAT(0x2D);

    Send_CMD(ST7735_FRMCTR3);
    Send_DAT(0x01);
    Send_DAT(0x2C);
    Send_DAT(0x2D);
    Send_DAT(0x01);
    Send_DAT(0x2C);
    Send_DAT(0x2D);


    Send_CMD(ST7735_INVCTR);
    Send_DAT(0x07);

    Send_CMD(ST7735_PWCTR1);
    Send_DAT(0xA2);
    Send_DAT(0x02);
    Send_DAT(0x84);

    Send_CMD(ST7735_PWCTR2);
    Send_DAT(0xC5);
 
    Send_CMD(ST7735_PWCTR3);
    Send_DAT(0x0A);
    Send_DAT(0x00);

    Send_CMD(ST7735_PWCTR4);
    Send_DAT(0x8A);
    Send_DAT(0x2A);

    Send_CMD(ST7735_PWCTR5);
    Send_DAT(0x8A);
    Send_DAT(0xEE);
    Send_CMD(ST7735_VMCTR1);
    Send_DAT(0x0E);
    Send_CMD(ST77XX_INVOFF);
    Send_CMD(ST77XX_MADCTL);
    Send_DAT(0xC0);
    Send_CMD(ST77XX_COLMOD);
    Send_DAT(0x05);
    Send_CMD(ST7735_GMCTRP1);
    Send_DAT(0x02);
    Send_DAT(0x1C);
    Send_DAT(0x07);
    Send_DAT(0x12);
    Send_DAT(0x37);
    Send_DAT(0x32);
    Send_DAT(0x29);
    Send_DAT(0x2D);
    Send_DAT(0x29);
    Send_DAT(0x25);
    Send_DAT(0x2B);
    Send_DAT(0x39);
    Send_DAT(0x00);
    Send_DAT(0x01);
    Send_DAT(0x03);
    Send_DAT(0x10);
    Send_CMD(ST7735_GMCTRN1);
    Send_DAT(0x03);
    Send_DAT(0x1D);
    Send_DAT(0x07);
    Send_DAT(0x06);
    Send_DAT(0x2E);
    Send_DAT(0x2C);
    Send_DAT(0x29);
    Send_DAT(0x2D);
    Send_DAT(0x2E);
    Send_DAT(0x2E);
    Send_DAT(0x37);
    Send_DAT(0x3F);
    Send_DAT(0x00);
    Send_DAT(0x00);
    Send_DAT(0x02);
    Send_DAT(0x10);
    Send_CMD(ST77XX_NORON);
    Delay(10);
    Send_CMD(ST77XX_DISPON);
    Delay(100);
    CS_H;//ChipSelect Up
}
void SetWindow(uint16_t startX, uint16_t startY, uint16_t stopX, uint16_t stopY) {
   Send_CMD(0x2A);
   Send_DAT(0);
   Send_DAT(startX);
   Send_DAT(0);
   Send_DAT(stopX);   
   Send_CMD(0x2B);
   Send_DAT(0);
   Send_DAT(startY);
        Send_DAT(0);
   Send_DAT(stopY);
}

void bufer()
{
        uint16_t x = 0, y = 0;
        SetWindow(10, 10, 128, 160);
   Send_CMD(0x2C);
        while(x++ <= 159)
        {
          y=0;
          while(y++ <=  127)
          {
            Send_DAT16(0xFF00);//buf[128][160];
          }
        }
}


Изображение

Ну и соответственно вызывается ини потом буффер

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 22:04:40

У L476 FIFO на SPI и команда SPI1->DR = dat; записывает два байта. Переделайте на байтовый доступ там где это надо.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 22:09:33

Команды 8 битные передаются при стирании флага SPI1->CR1 &= ~SPI_CR1_CRCL;, а 16 битные при установке. Или я не то что то понял

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 22:20:41

Команды 8 битные передаются при стирании флага SPI1->CR1 &= ~SPI_CR1_CRCL;, а 16 битные при установке. Или я не то что то понял

Нужно ещё и обращение к порту на 8 бит переделать.
*((__IO uint8_t *)&SPI1->DR) = dat;
И сам dat сделать uint8_t.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 22:27:49

Команды 8 битные передаются при стирании флага SPI1->CR1 &= ~SPI_CR1_CRCL;, а 16 битные при установке. Или я не то что то понял

Нужно ещё и обращение к порту на 8 бит переделать.
*((__IO uint8_t *)&SPI1->DR) = dat;
И сам dat сделать uint8_t.


Там uint8_t стоит dat.
Заработало. Но не понятно почему. Там написано в рефе по умолчанию CRCL не записан что соответствует 8 бит. я его еще и стираю на всякий. Почему не работало без
Код:
*((__IO uint8_t *)&SPI1->DR)  = dat;
вообще не понятно. инициализация же работала

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 22:34:16

1. Читайте RM, там всё есть
СпойлерИзображение
изображение_2024-03-07_223300122.png
(37.39 KiB) Скачиваний: 27

2. Посмотрите ассемблерный листинг обоих вариантов и всё поймёте.
3. Разрядность dat вообще не причём.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Чт мар 07, 2024 23:29:03

Спасибо вам большое ребята! Очень выручили а то я уже нос повесил.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Пт мар 08, 2024 10:03:30

TEPEM, предлагаю слегка облагородить инициализацию. Ссылка на Compiler Explorer.
СпойлерИзображение
изображение_2024-03-08_095816011.png
(45.49 KiB) Скачиваний: 51
Ещё и размер кода уменьшится.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Пт мар 08, 2024 14:02:29

VladislavS, можно же просто оформить значения инита в массив констант и оттуда в цикле вычитывать. Зачем эти пляски с объектами?

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Пт мар 08, 2024 14:17:30

VladislavS, можно же просто оформить значения инита в массив констант и оттуда в цикле вычитывать.
Собственно так и сделано. Только более современными средствами.

Зачем эти пляски с объектами?
Где вы там объекты увидели? Покажите хоть один.

PS: Насчёт зачем. Я смею утверждать, что этот код лучше оптимизируется компилятором.

Re: Микроконтроллеры STM32 - тонкости работы, отладочные пла

Сб мар 09, 2024 10:27:53

Где вы там объекты увидели? Покажите хоть один.

PS: Насчёт зачем. Я смею утверждать, что этот код лучше оптимизируется компилятором.

По ошибке бегло зацепился за токен class и обращение к членам. А потом уже увидел структуру. Ну да, так тоже можно, но я не уверен, что такая погоня за универсальностью (и удобством для человека) будет более оптимальным решением. Ну да ладно, решение достаточно изящно.
Ответить