Сделал софтовый 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);
}
↓ спойлер ↓ Третий и четвертый светодиоды не работают... :)
ы. Как ни странно задержки в код не добавлял совсем...
А вот железный 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;
}
Уффф. Чтение осилил.
Оказывается бит
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-ре первых сегмента счёт, на других вывод кода нажатой кнопки.