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

Приветствую, друзья!

Передо мной стоит задача: подключить камень stm32f103c8t6 по SPI через MAX7219 к семисегментнику.

Подключал по схеме:
 

Скрытый текст

image.thumb.png.0607be121bfff7889a5951edd218525c.png

 

Выясняется, что у меня ничего не работает. Понять почему я, увы, не могу.

Функции инициализации SPI и отправки данных:
 

Скрытый текст

image.png.7c366dc4666f252079f14caa3e68c60f.pngimage.thumb.png.1d8968e60119c6cec59106a66c07d2af.png

 

Чтобы понять проблему, я подключил логический анализатор ко всем трем выводам(MOSI, SCK, SS):
 

Скрытый текст

image.thumb.png.2ca30b09905433721a954076b7dddca8.png

 

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

Пробовал добавить задержку в функции отправки, подумав, что, может быть, мой анализатор не фиксирует их. На что я получил ошибки в отправляемых данных:

Скрытый текст

image.thumb.png.b1344a83f101ce327e1e10a498177373.png


Не понимаю, что я сделал не так...

Буду очень рад, если Вы подскажете!
Заранее большое спасибо!

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


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

У Вас на схеме из МАХ-а выходят сигналы:

DIG1(с двух контактов??), DIG3, DIG4.

А на индикатор приходят сигналы:

DIG1, DIG2(откуда он берётся) и два  DIG3.

Это так задумано?

 

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


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

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

Это так задумано?

Спасибо за замечание!
Перепутал немного, неправильно составил.
 

Скрытый текст

image.thumb.png.9e0af6654b6a00d1669e0c0cf0debb7c.png

 

47 минут назад, x893 сказал:

Сделайте ногодрыгом по диаграмме от МАХ

Согласно диаграмме, CS на нуле перед началом передачи и на единице - после.
image.thumb.png.6993c439f0778a7e4f0389fc76624912.png

 

В этом-то и проблема: у меня через анализатор видно, что CS поднимается после !всей! передачи, а это - 16 байт ( 8 функций, каждая функция отправляет 2 байта). 
Я не понимаю, в чем ошибка в коде. Почему у меня перещелкивается CS только после всей передачи, ведь я в функции управляю им. По логике, CS должен до и после выполнения функции дергаться, но этого, к сожалению, не видно.

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


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

23 minutes ago, oldbrowze said:

Почему у меня перещелкивается CS только после всей передачи, ведь я в функции управляю им. По логике, CS должен до и после выполнения функции дергаться, но этого, к сожалению, не видно.

1. Код лучше выкладывать текстом, а не картинками.

2. Возможно флаг SPI_SR_BSY не успевает установиться до того как вы его начали проверять.

    Попробуйте либо вести задержку перед проверкой этого флага, либо проверять флаг SPI_SR_RXNE.

 

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


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

1 час назад, oldbrowze сказал:

По логике, CS должен до и после выполнения функции дергаться, но этого, к сожалению, не видно.

Потому что нет никакой паузы между установкой CS=1 и последующей CS=0. Быстродействие GPIO гораздо ниже, чем у CPU и несколько тактов задержки на выполнение нескольких команд - крайне мало. К тому же - ёмкость линий на плате !=0, мгновенно напряжение на них не может изменяться.

PS: Для манипуляций с отдельными ногами GPIO сделали специальный регистр BSRR. Использование ODR - чревато.

PPS: То что у вас нарисовано в __delay() - это не задержка. Почитайте хоть немного раздел "Для начинающих" - 100500 раз уже об этом твердилось.

 

Хоть немного включите голову и подумайте над вопросами:

1. Какая тактовая частота у моего CPU?

2. Какова длительность(тактов) лог."1" между GPIOB->ODR |= ... и GPIOB->ODR &= ~... ?

3. Какова частота сэмплирования моего лог.анализатора? Какие минимальные по длительности сигналы он может захватить?

4. На какой частоте работает GPIO в моём МК?

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


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

30 minutes ago, jcxz said:

Хоть немного включите голову и подумайте над вопросами:

0. Зачем это всё надо ?!

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


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

1 минуту назад, x893 сказал:

0. Зачем это всё надо ?!

Включать голову? А можно без неё писать код?

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


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

1 час назад, jcxz сказал:

Хоть немного включите голову и подумайте над вопросами

Спасибо, подумал. 


Я действительно уже мало думал под конец, отчаялся. Хотя, если честно, я правда не додумался, что ошибка в этом..

У меня действительно все получилось. 

Скрытый текст

image.thumb.png.78e811b7dfdd95d35ee182574603155e.png


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

Команды отправляю согласно даташиту, передача(дрыг ноги CS) удовлетворяет даташиту..
 

LED_I::send_command(0x9, 0xFF); // режим декодирования
LED_I::send_command(0xB, 0x3); // количество разрядов
LED_I::send_command(0xA, 0x5); // яркость
LED_I::send_command(0xC, 0x1); // включаем

LED_I::send_command(0x1, 0x1); // единица

 

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


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

Было дело, баловался я с MAX7219, и как раз на STM32F103.

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


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

Моя рекомендация на данном этапе: сделайте read-back регистров, которые Вы записали. Когда считаете ровно то, что было записано, можно будет считать, что со связью все в порядке. Если же там белиберда - сами понимаете... Сейчас пока нет уверенности, что регистры получают ровно то, что Вы пишете. А пока нет уверенности в этом - дальше смысла смотреть просто нет.

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


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

Попробуйте факт окончания передачи отслеживать по двум флагам: первично по TXE  и лишь вторично по BSY. Уже не вспомню, но были какие-то "приколы" с BSY-флагом в F1xx семействе.

void foo(bar)
{
	GPIOB->ODR &= ~GPIO_ODR11;
	//.....

	while (!(SPI1->SR & SPI_SR_TXE));
	while (SPI1->SR & SPI_SR_BSY);

	GPIOB->ODR |= GPIO_ODR11;
}

 

upd BSY устанавливается с задержкой. Т.е. факт начала передачи отслеживаете по TXE==0. Он становится '0' сразу же после записи слова данных в SPI_DR. После первого такта SCLK, когда слово из временного буфера выгрузилось в сдвиговый регистр, флаг TXE становится '1' и в дело вступает BSY, который к этому времени гарантированно установился в '1'.

В общем в RefManual почитайте, сейчас нет времени в это окунаться.

image.thumb.png.2aa999d80b1555d444aa65b5b73e9532.png

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


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

19.11.2021 в 20:46, dimka76 сказал:

2. Возможно флаг SPI_SR_BSY не успевает установиться до того как вы его начали проверять.

    Попробуйте либо вести задержку перед проверкой этого флага, либо проверять флаг SPI_SR_RXNE.

 

19 часов назад, Sergey_Aleksandrovi4 сказал:

upd BSY устанавливается с задержкой. Т.е. факт начала передачи отслеживаете по TXE==0. Он становится '0' сразу же после записи слова данных в SPI_DR. После первого такта SCLK, когда слово из временного буфера выгрузилось в сдвиговый регистр, флаг TXE становится '1' и в дело вступает BSY, который к этому времени гарантированно установился в '1'.

В общем в RefManual почитайте, сейчас нет времени в это окунаться.

 

Да, полагаю, мой анализатор просто не успевает углядеть. Поставил небольшую задержку, все успешно. 
Спасибо еще раз.


 

21 час назад, Arlleex сказал:

Моя рекомендация на данном этапе: сделайте read-back регистров, которые Вы записали. Когда считаете ровно то, что было записано, можно будет считать, что со связью все в порядке. Если же там белиберда - сами понимаете... Сейчас пока нет уверенности, что регистры получают ровно то, что Вы пишете. А пока нет уверенности в этом - дальше смысла смотреть просто нет.

Считать с другого устройства у меня, увы, нет возможности. 

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

И, все-таки, подскажите, пожалуйста, что можно сделать с этим:
 

Скрытый текст
23 часа назад, oldbrowze сказал:

Спасибо, подумал. 


Я действительно уже мало думал под конец, отчаялся. Хотя, если честно, я правда не додумался, что ошибка в этом..

У меня действительно все получилось. 

  Показать содержимое

image.thumb.png.78e811b7dfdd95d35ee182574603155e.png


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

Команды отправляю согласно даташиту, передача(дрыг ноги CS) удовлетворяет даташиту..
 



LED_I::send_command(0x9, 0xFF); // режим декодирования
LED_I::send_command(0xB, 0x3); // количество разрядов
LED_I::send_command(0xA, 0x5); // яркость
LED_I::send_command(0xC, 0x1); // включаем

LED_I::send_command(0x1, 0x1); // единица

 

 


Уже сравниваю с даташитом по анализатору: диаграмма идентична, если так можно выразится. Но все равно не заводится микросхема. 

 

Скрытый текст

void LED_I::send_command(const uint8_t &address, const uint8_t &command)
{
    GPIOB->BRR |= GPIO_BRR_BR11;
    //while(SPI1->SR & SPI_SR_BSY);
    
    //GPIOB->BRR |= GPIO_BRR_BR11;

    SPI1->DR = (address << 8) | command; // отслыем первым байтом адрес регистра, втором - команду для регистра
    //__delay(_FUNCTION_DELAY);

    //GPIOB->BSRR |= GPIO_BSRR_BS11;
    while (!(SPI1->SR & SPI_SR_TXE));
    //while (SPI1->SR & SPI_SR_RXNE);
    while(SPI1->SR & SPI_SR_BSY);

    GPIOB->BSRR |= GPIO_BSRR_BS11;

    __delay(1);
}

void LED_I::init()
{
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN; // запускаем тактирование SPI, PB
    
    SPI1->CR1 |= (1 << SPI_CR1_DFF_Pos)     // 16-битная передача
                | (1 << SPI_CR1_SSM_Pos)     // программный SS
                | (1 << SPI_CR1_SSI_Pos)
                | (1 << SPI_CR1_BIDIMODE_Pos)
                | (1 << SPI_CR1_BIDIOE_Pos)
                | (0 << SPI_CR1_LSBFIRST_Pos)
                | (0b111 << SPI_CR1_BR_Pos)
                | (1 << SPI_CR1_MSTR_Pos)
                | (0 << SPI_CR1_CPHA_Pos)
                | (0 << SPI_CR1_CPOL_Pos);
    SPI1->CR1 |= (1 << SPI_CR1_SPE_Pos);
    //SCK
    GPIOA->CRL |= (0b10 << GPIO_CRL_CNF5_Pos) | (0b11 << GPIO_CRL_MODE5_Pos);
  
    //CS
    GPIOB->CRH |= (0b00 <<GPIO_CRH_CNF11_Pos) | (0b11 << GPIO_CRH_MODE11_Pos);
    GPIOB->BSRR |= GPIO_BSRR_BS11;
    //MOSI
    GPIOA->CRL |= (0b10 << GPIO_CRL_CNF7_Pos) | (0b11 << GPIO_CRL_MODE7_Pos);
    while(SPI1->SR & SPI_SR_MODF);
}


int main()
{
    RCC_Init(); //инициализация тактирования
    LED_I::init();

    LED_I::send_command(0x9, 0xFF); // режим декодирования
    LED_I::send_command(0xB, 0x3); // количество разрядов
    LED_I::send_command(0xA, 0x5); // яркость
    LED_I::send_command(0xC, 0x1); // включаем

    LED_I::send_command(0x1, 0x1); // единица

    while(true);
    return 0;
}

 

 

 

Хотя бы, в какую сторону смотреть..Где я мог допустить ошибку.


Диаграммы с анализатора:
 

Скрытый текст

image.thumb.png.cc0546b97c018a26e112c781ad39d697.pngimage.thumb.png.18072ae00dfeb0d983a418c43237b7f8.pngimage.thumb.png.d1c63270ea5c339fc3b0d2cfe366813a.pngimage.thumb.png.6d51c37b3ca6e68f08c7f2760fb6dbb1.pngimage.thumb.png.a5fec13988ad51f41952254674ca5b18.pngimage.thumb.png.09a18c907f5e1bfd0301f3c282154fcf.png

 

Изменено пользователем oldbrowze

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


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

Что-то я не догоняю, как Вы отлаживаетесь? Что значит "считать с другого устройства"?

Я говорю про обратное чтение того, что записали в микросхему с последующей сверкой.

Вы же на реальной железке отлаживаетесь?

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


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

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

Вы же на реальной железке отлаживаетесь?

Да.

Вы меня извините, может я не развился еще до таких знаний, но как я сделаю сам read-back данных?
Как я Вас понял: я делаю slave-устройство, читаю с него и сверяю с отправленными данными. Но как сделать с MAX7219 - не представляю.

Наверное, глупо выгляжу))

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


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

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...