К некоторым в старости приходит не мудрость, а маразм...

Меню навигации для мобильных

TM1638

Автор zenon, 07 Июль, 2023, 13:40

« предыдущая - следующая »

zenon

Сделал софтовый SPI на пробу для модуля на TM1638 с кнопками.
Макетом послужила лишняя плата приёмника.


main
↓ спойлер ↓
#include <stm32f0xx.h>
#include "tm1638_softspi.h"
// PIN_STB // PB4 STB SPI1_MISO // SPI3_CS_SET  SPI3_CS_CLR
// PIN_CLK // PB3 CLK SPI1_SCK  // SPI3_CLK_SET SPI3_CLK_CLR
// PIN_DIO // PB5 DIO SPI1_MOSI // SPI3_DIO_SET SPI3_DIO_CLR
volatile uint32_t ttms = 0;
volatile uint32_t pa2  = 0;
#define pin_toggle(gpioport, gpios)  do{  \
        register uint32_t __port = gpioport->ODR;  \
        gpioport->BSRR = ((__port & (gpios)) << 16) | (~__port & (gpios));}while(0)

void gpio_init(void)
{
  RCC->AHBENR  |= RCC_AHBENR_GPIOAEN  | RCC_AHBENR_GPIOBEN;

  GPIOA->MODER    &= ~ GPIO_MODER_MODER2;
  GPIOA->MODER    |=   GPIO_MODER_MODER2_0;
  GPIOA->OTYPER   &= ~ GPIO_OTYPER_OT_2;
  GPIOA->OSPEEDR  |=   GPIO_OSPEEDER_OSPEEDR2_0;
  
  GPIOB->MODER    &= ~( GPIO_MODER_MODER3       | GPIO_MODER_MODER4       | GPIO_MODER_MODER5 );
  GPIOB->MODER    |=  ( GPIO_MODER_MODER3_0     | GPIO_MODER_MODER4_0     | GPIO_MODER_MODER5_0 ) ;
  GPIOB->OTYPER   &= ~( GPIO_OTYPER_OT_3        | GPIO_OTYPER_OT_4        | GPIO_OTYPER_OT_5 ) ;
  GPIOB->OSPEEDR  |=  ( GPIO_OSPEEDER_OSPEEDR3_0|GPIO_OSPEEDER_OSPEEDR4_0 | GPIO_OSPEEDER_OSPEEDR5_0 );
}
void rcc_sysclockinit(void)
{
  RCC->CR = RCC_CR_HSEON;
  while(! (RCC->CR & RCC_CR_HSERDY));
  RCC->CFGR2 = RCC_CFGR2_PREDIV_DIV2;
  RCC->CFGR  = RCC_CFGR_PLLMUL4 | 
               RCC_CFGR_PLLSRC_HSE_PREDIV;
  RCC->CR |= RCC_CR_PLLON;
  FLASH->ACR = _VAL2FLD(FLASH_ACR_LATENCY, 1) | FLASH_ACR_PRFTBE;
  while(! (RCC->CR & RCC_CR_PLLRDY));
  RCC->CFGR |= RCC_CFGR_SW_PLL;
}

void blink_(uint16_t freq)
{
  if (pa2 > ttms || ttms - pa2 > freq)
  {
    pin_toggle(GPIOA, 1<<2);
    pa2 = ttms;
  }
}

int main(void) {
  uint16_t key;
  rcc_sysclockinit();
  SysTick_Config(48000);
  gpio_init();
  tm1638_init();
  do {
    blink_(499);
    key = tm1638_read_key();
    if (key < 8) {
      while (tm1638_read_key() == key)
        ;
      if (key == 0) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 1) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 2) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 3) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 4) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 5) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 6) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 7) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      }
    }
  } while (1);
}

void SysTick_Handler(void) 
{
  ++ttms;
}
[свернуть]


tm1638_softspi
↓ спойлер ↓
#include "tm1638_softspi.h"

#define DATA_COMMAND    0X40
#define DISP_COMMAND    0x80
#define ADDR_COMMAND    0XC0

#define SPI3_DIO_SET GPIOB->BSRR |= GPIO_BSRR_BS_5
#define SPI3_DIO_CLR GPIOB->BSRR |= GPIO_BSRR_BR_5
#define SPI3_CLK_SET GPIOB->BSRR |= GPIO_BSRR_BS_3
#define SPI3_CLK_CLR GPIOB->BSRR |= GPIO_BSRR_BR_3
#define SPI3_CS_SET  GPIOB->BSRR |= GPIO_BSRR_BS_4
#define SPI3_CS_CLR  GPIOB->BSRR |= GPIO_BSRR_BR_4
#define SPI3_CHECK_DIO pin_read(GPIOB, 1<<5)


unsigned char code_tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};

void tm1638_write_byte(unsigned char data) {
  unsigned char i;
  for (i = 0; i < 8; i++) {
    SPI3_CLK_CLR; 
    if (data & 0x01)
      SPI3_DIO_SET;
    else
      SPI3_DIO_CLR; 
    data >>= 1;
    SPI3_CLK_SET; 
  }
}

unsigned char tm1638_read_byte(void) {
  unsigned char i;
  unsigned char temp = 0;
  SPI3_DIO_SET;
  for (i = 0; i < 8; i++) {
    temp >>= 1;
    SPI3_CLK_CLR;
    if (SPI3_CHECK_DIO)
      temp |= 0x80;
    SPI3_CLK_SET;
  }
  return temp;
}

void tm1638_write_com(unsigned char cmd) {
  SPI3_CS_CLR;
  tm1638_write_byte(cmd);
  SPI3_CS_SET;
}

unsigned char tm1638_read_key(void) {
  unsigned char c[4], i, key_value = 0;
  SPI3_CS_CLR;
  tm1638_write_byte(0x42);
  for (i = 0; i < 4; i++)
    c[i] = tm1638_read_byte();
  SPI3_CS_SET;
  for (i = 0; i < 4; i++)
    key_value |= c[i] << i;
  for (i = 0; i < 8; i++)
    if ((0x01 << i) == key_value)
      break;
  return i;
}

void tm1638_write_data(unsigned char add, unsigned char data) {
  tm1638_write_com(0x44);
  SPI3_CS_CLR;
  tm1638_write_byte(0xc0 | add);
  tm1638_write_byte(data);
  SPI3_CS_SET;
}

void tm1638_write_led(unsigned char led_flag) {
  unsigned char i;
  for (i = 0; i < 8; i++) {
    if (led_flag & (1 << i))
      tm1638_write_data(2 * i + 1, 1);
    else
      tm1638_write_data(2 * i + 1, 0);
  }
}

void tm1638_init(void) {
  unsigned char i;
  tm1638_write_com(0x8b);
  tm1638_write_com(0x40);
  SPI3_CS_CLR;
  tm1638_write_byte(0xc0);
  for (i = 0; i < 16; i++)
    tm1638_write_byte(0x00);
  SPI3_CS_SET;
}
extern unsigned char num[8];
void tm1638_tube_dip(uint16_t pos, uint16_t data) {
  tm1638_write_data(pos * 2, code_tab[data]);
  tm1638_write_led(1 << data);
}
[свернуть]


↓ спойлер ↓
[свернуть]
Третий и четвертый светодиоды не работают... :)
ы. Как ни странно задержки в код не добавлял совсем...
https://github.com/minamonra/

zenon

А вот железный SPI заставил опять подключить анализатор, сделал отправку.
Примерчик размещу на гитхабе, заминка в основном была из-за того, что микросхема принимает байты младшим битом вперёд (LSBFIRST).
Вот такой инит и передача байта вышли:
#define CS_SET GPIOB->BSRR |= GPIO_BSRR_BS_4
#define CS_CLR GPIOB->BSRR |= GPIO_BSRR_BR_4

static void spi_init(void)
{
  RCC->AHBENR   |= RCC_AHBENR_GPIOBEN;
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
  // SCK  PB3
  GPIOB->MODER |= GPIO_MODER_MODER3_1;  // alternate function
  // MOSI  PB5
  GPIOB->MODER |= GPIO_MODER_MODER5_1;  // alternate function
  // soft nCS   PB4
  GPIOB->MODER |= GPIO_MODER_MODER4_0; // PB4 as output
  GPIOB->OSPEEDR  |=  ( GPIO_OSPEEDER_OSPEEDR4_0);
  CS_SET; //GPIOB->ODR = GPIO_ODR_4; // deselect
  SPI1->CR1 |= SPI_CR1_BR_1; // set prescaler FCY=16MHz / prescaler(8) = 2 MHz (0b010)
  SPI1->CR1 |= SPI_CR1_LSBFIRST; // !!
  SPI1->CR1 |= SPI_CR1_MSTR; // бит мастера (SPI_CR1_MSTR)
  SPI1->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; // software slave CS management & internal slave select
  SPI1->CR2 |= SPI_CR2_FRXTH; // бит наличия данных в очереди на четверть длины - 8 бит (SPI_CR2_FRXTH)
  SPI1->CR2 |= SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0; //8-bit
  SPI1->CR1 |= SPI_CR1_SPE; // SPI вкл
}
отправка:
uint8_t spi_send_byte(uint8_t data)
{
  while (!(SPI1->SR & SPI_SR_TXE)); // TX buffer is empty
  *(volatile uint8_t *) & SPI1->DR = data;
  while (!(SPI1->SR & SPI_SR_RXNE)); // while (!(SPI1->SR & SPI_SR_BSY)); //
  return *(volatile uint8_t *) & SPI1->DR;
}
https://github.com/minamonra/

zenon

#2
Уффф. Чтение осилил.
Оказывается бит SPI_CR1_BIDIMODE надо включить, потом четыре байта прочесть.
uint8_t tm1638_get_key(void)
{
  uint8_t i, key_value = 0;
  CS_CLR;
  spi_send_byte(0x42);
  SPI1->CR1 |= SPI_CR1_BIDIMODE;  // вкл bi-directional mode
  for (i = 0; i < 4; i++)
    key_value |= spi_send_byte(0xFF) << i;
  CS_SET;
  SPI1->CR1 &= ~SPI_CR1_BIDIMODE; // выкл bi-directional mode
  return key_value;
}


:: добавлено 30 Июль, 2023, 20:27
Ну вот как-то так https://github.com/minamonra/my_stm_snippets/tree/main/F0/tm1638/tm1638hw
В мэйне код - 4-ре первых сегмента счёт, на других вывод кода нажатой кнопки.
https://github.com/minamonra/