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

Как переслать 64 бита в аппаратный регистр


le2x

Рекомендуемые сообщения

Добрый день коллеги!

Имеется микроконтроллер STM32F103C8, к нему подключен внешняя микросхема - регистр разрядностью 64 бита. Управление происходит по трем линиям:

LATCH_DIO  - разрешение записи в регистр (LOW)

CLK_DIO  - синхронизация

DATA_DIO  - данные (последовательно, побитно)

Очень напоминает работу SPI поэтому и решил для начала попробовать приспособить его. Но ничего не вышло так-как по SPI в одном пакете может передать максимально 16 бит данных.

Полагаю что необходимо использовать GPIO для этого. Но вот беда не могу понять как из переменной извлечь биты данных и установить их на DATA_DIO последовательно? Или может быть есть еще какие-то решения? Разработку веду в CoIDE v.1.7

Изменено пользователем le2x
ошибка
Ссылка на комментарий
Поделиться на другие сайты

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

Но ничего не вышло так-как по SPI в одном пакете может передать максимально 16 бит данных

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

Для этого служит DMA.

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

4 часа назад, le2x сказал:

может передать максимально 16 бит данных

Вот и передайте 4 раза по 16 бит. А потом активируйте сигнал LATCH_DIO, по которому все переданные биты одним махом запишутся в регистр.

Для этого линией LATCH_DIO надо управлять вручную, а не соединять с сигналом SS от SPI. То есть на какой-то свободный GPIO выход вешаете этот самый LATCH_DIO и дергаете им, когда все 64 бита передано.

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

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

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

Вот и передайте 4 раза по 16 бит. А потом активируйте сигнал LATCH_DIO, по которому все переданные биты одним махом запишутся в регистр.

Для этого линией LATCH_DIO надо управлять вручную, а не соединять с сигналом SS от SPI. То есть на какой-то свободный GPIO выход вешаете этот самый LATCH_DIO и дергаете им, когда все 64 бита передано.

Типа вот так что ли?

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"

void delay (uint32_t time_delay) //функция задержки
{
    uint32_t i;
    for (i=0;i<time_delay;i++);
}

int main(void)
{
    // настраиваем выводы 4-7 порта A  на альтернативный режим работы
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // LATCH_DIO  - разрешение записи в регистр (LOW)
    GPIO_InitTypeDef latch;
    latch.GPIO_Speed = GPIO_Speed_2MHz;
    latch.GPIO_Mode  = GPIO_Mode_Out_PP;
    latch.GPIO_Pin = GPIO_Pin_8 ;
    GPIO_Init(GPIOA, &latch);
    GPIO_SetBits(GPIOA, GPIO_Pin_8); //устанывливаем на линнии запрет приема данных

    //выводы под SPI
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    gpio.GPIO_Mode  = GPIO_Mode_AF_PP;
    gpio.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &gpio);

    // настраиваем SPI1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_InitTypeDef spi;
    spi.SPI_Direction = SPI_Direction_1Line_Tx;
    spi.SPI_Mode = SPI_Mode_Master;
    spi.SPI_DataSize = SPI_DataSize_16b;
    spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
    spi.SPI_CPHA = SPI_CPHA_1Edge; //фронт синхронизации
    spi.SPI_NSS = SPI_NSS_Soft;
    spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    spi.SPI_FirstBit = SPI_FirstBit_MSB; //передавать сначала младший бит
    spi.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &spi);
    SPI_Cmd(SPI1, ENABLE);

    GPIO_ResetBits(GPIOA, GPIO_Pin_8);
    SPI_I2S_SendData(SPI1, 0x80F1);
    SPI_I2S_SendData(SPI1, 0x80F2);
    SPI_I2S_SendData(SPI1, 0x80F4);
    SPI_I2S_SendData(SPI1, 0x80F8);
    GPIO_SetBits(GPIOA, GPIO_Pin_8);

    while(1)
    {

    }
}

 

Так не работает. Причем могу за комментировать строки GPIO_ResetBits(GPIOA, GPIO_Pin_8); GPIO_SetBits(GPIOA, GPIO_Pin_8); результат не меняется

Кстати пытаюсь к STM32 подключить Arduino Multifunction Shield http://arduinolearning.com/code/multi-function-shield-examples.php

И у них оно примерно так и работает:
 

digitalWrite(LATCH_DIO,LOW);
shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);
shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );
digitalWrite(LATCH_DIO,HIGH);

Проверял код из примера в ссылке на Arduino mega 2560,  этот шилд отлично все отображает

Изменено пользователем le2x
Ссылка на комментарий
Поделиться на другие сайты

Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. 

Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств. Подробнее параметры и результаты тестов новой серии PLM по ссылке.

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

31 minutes ago, le2x said:

SPI_I2S_SendData(SPI1, 0x80F1);

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

После последней передачи надо дождаться окончания передачи и затем устанавливать

34 minutes ago, le2x said:

GPIO_SetBits(GPIOA, GPIO_Pin_8);

Для начала можно просто поставить везде задержки без проверки флагов

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

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

34 минуты назад, le2x сказал:

Так не работает.

Возьмите нормальный пример SPI из интернета для Coocox. В Вашей программе не хватает проверки: перед отправкой очередного слова нужно проверять закончилась ли предыдущая процедура передачи.

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, 0x80F2);
и т.д.

Какая конкретно внешняя микросхема?

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

    GPIO_ResetBits(GPIOA, GPIO_Pin_8);
    SPI_I2S_SendData(SPI1, 0x80F1);
    //delay (100000);
    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) || SPI1->SR & SPI_I2S_FLAG_BSY );
    SPI_I2S_SendData(SPI1, 0x80F2);
    //delay (100000);
    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) || SPI1->SR & SPI_I2S_FLAG_BSY );
    SPI_I2S_SendData(SPI1, 0x80F4);
    //delay (100000);
    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) || SPI1->SR & SPI_I2S_FLAG_BSY );
    SPI_I2S_SendData(SPI1, 0x80F8);
    //delay (100000);
    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) || SPI1->SR & SPI_I2S_FLAG_BSY );
    GPIO_SetBits(GPIOA, GPIO_Pin_8);

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

SPI_I2S_SendData(SPI1, 0x80F8);

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

SPI_I2S_SendData(SPI1, 0x80F4);

Хочу зажечь все четыре индикатора.

Изменено пользователем le2x
Ссылка на комментарий
Поделиться на другие сайты

Принципиальная электрическая схема и изображение платы во вложении.

Пины микроконтроллера:

LATCH_DIO - GPIO_Pin_8

CLK_DIO - GPIO_Pin_5

DATA_DIO - GPIO_Pin_7

apc220-bluetooth-voice-recognition-module.jpg

1457533970_untitled.png

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

Через spi должно б работать. Если нет, посомотрите примеры с 595 сдвиговым регистром, там всё просто, например так:

uint64_t inputData;    
for (i = 0; i < 64; i++)
	{
	if (inputData & 0x80000000)
	    {
	    HAL_GPIO_WritePin(DATA_DIO_PORT, DATA_DIO_PIN,
		    GPIO_PIN_SET);
	    }
	else
	    {
	    HAL_GPIO_WritePin(DATA_DIO_PORT, DATA_DIO_PIN,
		    GPIO_PIN_RESET);
	    }
	HAL_GPIO_WritePin(MCU_595_SH_GPIO_Port, MCU_595_SH_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(MCU_595_SH_GPIO_Port, MCU_595_SH_Pin, GPIO_PIN_RESET);
	inputData <<= 1;
	}

Можно между подъемом и спуском строба задержку небольшую сделать, что бы фронт успел нарастать. Но вообще должно бы и с spi работать. СPOL и СPHA правильно настроены?

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

Я кажется понял свою ошибку, посмотрел внимательнее на схему и понял что не нужно никаких 64 бита передавать в регистр а всего 16. Первые байт отвечают за номер индикатора а второй значение на сегментах. Так что должно все получиться с SPI.

Цитата

Поставьте вмесо F8, FF и должены включитьсявсе индикаторы.

Да действительно так и есть, загорелись все 4 индикатора, правда не цифрами а кракозябрами, осталось подобрать правильные коды символов

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

В общем заработало в таком варианте

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"

void delay (uint32_t time_delay) //функция задержки
{
    uint32_t i;
    for (i=0;i<time_delay;i++);
}

int main(void)
{
    // настраиваем выводы 4-7 порта A  на альтернативный режим работы
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // LATCH_DIO  - разрешение записи в регистр (LOW)
    GPIO_InitTypeDef latch;
    latch.GPIO_Speed = GPIO_Speed_2MHz;
    latch.GPIO_Mode  = GPIO_Mode_Out_PP;
    latch.GPIO_Pin = GPIO_Pin_8 ;
    GPIO_Init(GPIOA, &latch);

    //выводы под SPI
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    gpio.GPIO_Mode  = GPIO_Mode_AF_PP;
    gpio.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &gpio);

    // настраиваем SPI1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_InitTypeDef spi;
    spi.SPI_Direction = SPI_Direction_1Line_Tx;
    spi.SPI_Mode = SPI_Mode_Master;
    spi.SPI_DataSize = SPI_DataSize_16b;
    spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
    spi.SPI_CPHA = SPI_CPHA_2Edge; //фронт синхронизации
    spi.SPI_NSS = SPI_NSS_Soft;
    spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    spi.SPI_FirstBit = SPI_FirstBit_MSB; //передавать сначала младший бит
    spi.SPI_CRCPolynomial = 15;
    SPI_Init(SPI1, &spi);
    SPI_Cmd(SPI1, ENABLE);

    while(1)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_8);
        SPI_I2S_SendData(SPI1, 0xC0F1);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        GPIO_ResetBits(GPIOA, GPIO_Pin_8);
        delay(10000);

        GPIO_SetBits(GPIOA, GPIO_Pin_8);
        SPI_I2S_SendData(SPI1, 0xF9F2);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        GPIO_ResetBits(GPIOA, GPIO_Pin_8);
        delay(10000);

        GPIO_SetBits(GPIOA, GPIO_Pin_8);
        SPI_I2S_SendData(SPI1, 0xA4F4);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        GPIO_ResetBits(GPIOA, GPIO_Pin_8);
        delay(10000);

        GPIO_SetBits(GPIOA, GPIO_Pin_8);
        SPI_I2S_SendData(SPI1, 0xB0F8);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        GPIO_ResetBits(GPIOA, GPIO_Pin_8);
        delay(10000);

    }
}

Сначала нужно установить 1 на LATCH_DIO, затем передать два байта по SPI, затем установить 0 на LATCH_DIO. Вот это как раз и странно, должно быть все наоборот. Получается LATCH_DIO нельзя подключить к SPI_NSS выходу, либо подключать через инвертор (элемент НЕ, транзистор по схеме с ОЭ). Но в примере для Arduino  все логично. Что тогда не так?

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

Во-первых, у Вас настройка SPI неправильная. Данные в 595 регистр задвигаются по положительному перепаду 0->1, поэтому, если полярность клоков выбрана Low, то фронт клоков нужно выбрать первый, т.е. по первому фронту после Low состояния клоков.

spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
spi.SPI_CPHA = SPI_CPHA_1Edge; //фронт синхронизации

Во-вторых, флаг SPI_I2S_FLAG_TXE означает, что регистр передачи SPI опустел. То есть данные из регистра TX перешли в сдвиговый регистр SPI и начали выталкиваться наружу. Другими словами установка флага SPI_I2S_FLAG_TXE в 1 не означает окончание передачи по SPI.

Для проверки окончания есть другой флаг SPI_I2S_FLAG_BSY, который = 1 в процессе передачи и = 0, когда передача закончилась.

 

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

Сначала нужно установить 1 на LATCH_DIO,

Сигнал LATCH_DIO записывает данные на выходные линии тоже по положительному перепаду 0->1. То есть после задвигания всех 16 битов нужно каким-то образом организовать такой перепад на линии LATCH_DIO.

Например, так

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
SPI_I2S_SendData(SPI1, 0xC0F1);// пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);

 

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

Уважаемый @Yurkin2015 вы абсолютно правы. Надо было мне сразу заглянуть в даташит на 74HC595

и тогда бы я увидел эту диаграмму.

Безымянный.png

Поправил фронт и полярность в настройках GPIO. Ваш код действительно работает. Также он работает и в таком варианте когда сначала на линию LATCH_DIO  устанавливаем 0, передаем данные по SPI c проверкой флагов и устанавливаем на LATCH_DIO = 1, так что теперь все логично и понятно. Спасибо. Осталось поиграть с SPI_NSS дабы не задействовать отдельную ногу под LATCH_DIO

Изменено пользователем le2x
Ссылка на комментарий
Поделиться на другие сайты

В общем понял что nss для работы в режиме slave и multimaster и что этот вариант мне не подходит управление осуществляю при помощи GPIO. Всем спасибо за помощь. Ниже рабочий код.

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //LATCH_DIO  - разрешение записи в регистр (LOW)
    GPIO_InitTypeDef latch;
    latch.GPIO_Speed = GPIO_Speed_2MHz;
    latch.GPIO_Mode  = GPIO_Mode_Out_PP;
    latch.GPIO_Pin = GPIO_Pin_8 ;
    GPIO_Init(GPIOA, &latch);

    //выводы под SPI CLK_DIO - GPIO_Pin_5, DATA_DIO - GPIO_Pin_7
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    gpio.GPIO_Mode  = GPIO_Mode_AF_PP;
    gpio.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &gpio);

    // настраиваем SPI1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_InitTypeDef spi;
    spi.SPI_Direction = SPI_Direction_1Line_Tx;
    spi.SPI_Mode = SPI_Mode_Master;
    spi.SPI_DataSize = SPI_DataSize_16b;
    spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
    spi.SPI_CPHA = SPI_CPHA_1Edge; //фронт синхронизации
    spi.SPI_NSS = SPI_NSS_Soft;
    spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    spi.SPI_FirstBit = SPI_FirstBit_MSB; //передавать сначала младший бит
    spi.SPI_CRCPolynomial = 15;
    SPI_Init(SPI1, &spi);
    SPI_Cmd(SPI1, ENABLE);


    while(1)
    {

    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
    	SPI_I2S_SendData(SPI1, 0xC0F1);// пишем в TX данные, начало передачи
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
    	GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
    	GPIO_SetBits(GPIOA, GPIO_Pin_8);

    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
    	SPI_I2S_SendData(SPI1, 0xF9F2);// пишем в TX данные, начало передачи
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
    	GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
    	GPIO_SetBits(GPIOA, GPIO_Pin_8);

    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
    	SPI_I2S_SendData(SPI1, 0xA4F4);// пишем в TX данные, начало передачи
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
    	GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
    	GPIO_SetBits(GPIOA, GPIO_Pin_8);

    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
    	SPI_I2S_SendData(SPI1, 0xB0F8);// пишем в TX данные, начало передачи
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
    	GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
    	GPIO_SetBits(GPIOA, GPIO_Pin_8);

    }
}

 

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

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

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

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

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

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...