le2x Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 (изменено) Добрый день коллеги! Имеется микроконтроллер STM32F103C8, к нему подключен внешняя микросхема - регистр разрядностью 64 бита. Управление происходит по трем линиям: LATCH_DIO - разрешение записи в регистр (LOW) CLK_DIO - синхронизация DATA_DIO - данные (последовательно, побитно) Очень напоминает работу SPI поэтому и решил для начала попробовать приспособить его. Но ничего не вышло так-как по SPI в одном пакете может передать максимально 16 бит данных. Полагаю что необходимо использовать GPIO для этого. Но вот беда не могу понять как из переменной извлечь биты данных и установить их на DATA_DIO последовательно? Или может быть есть еще какие-то решения? Разработку веду в CoIDE v.1.7 Изменено 18 сентября, 2017 пользователем le2x ошибка 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
ALEN&Co Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 1 час назад, le2x сказал: Но ничего не вышло так-как по SPI в одном пакете может передать максимально 16 бит данных SPI может передать сколько угодно, но нужно вовремя подавать ему эту информацию. Для этого служит DMA. 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
20% скидка на весь каталог электронных компонентов в ТМ Электроникс!Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!Перейти на страницу акции Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849
Yurkin2015 Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 4 часа назад, le2x сказал: может передать максимально 16 бит данных Вот и передайте 4 раза по 16 бит. А потом активируйте сигнал LATCH_DIO, по которому все переданные биты одним махом запишутся в регистр. Для этого линией LATCH_DIO надо управлять вручную, а не соединять с сигналом SS от SPI. То есть на какой-то свободный GPIO выход вешаете этот самый LATCH_DIO и дергаете им, когда все 64 бита передано. 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>> Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161
le2x Опубликовано 18 сентября, 2017 Автор Поделиться Опубликовано 18 сентября, 2017 (изменено) 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, этот шилд отлично все отображает Изменено 18 сентября, 2017 пользователем le2x 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
snn_krs Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 31 minutes ago, le2x said: SPI_I2S_SendData(SPI1, 0x80F1); После каждой передачи надо ждать освобождения регистра и только потом передавать новые данные. После последней передачи надо дождаться окончания передачи и затем устанавливать 34 minutes ago, le2x said: GPIO_SetBits(GPIOA, GPIO_Pin_8); Для начала можно просто поставить везде задержки без проверки флагов 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Yurkin2015 Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 34 минуты назад, le2x сказал: Так не работает. Возьмите нормальный пример SPI из интернета для Coocox. В Вашей программе не хватает проверки: перед отправкой очередного слова нужно проверять закончилась ли предыдущая процедура передачи. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, 0x80F2); и т.д. Какая конкретно внешняя микросхема? 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 18 сентября, 2017 Автор Поделиться Опубликовано 18 сентября, 2017 (изменено) 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); Хочу зажечь все четыре индикатора. Изменено 18 сентября, 2017 пользователем le2x 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Yurkin2015 Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 О, уже какие-то индикаторы появились. Что у Вас там за внешняя схема? Какие индикаторы и как они соединены? 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 18 сентября, 2017 Автор Поделиться Опубликовано 18 сентября, 2017 Принципиальная электрическая схема и изображение платы во вложении. Пины микроконтроллера: LATCH_DIO - GPIO_Pin_8 CLK_DIO - GPIO_Pin_5 DATA_DIO - GPIO_Pin_7 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
GOR23 Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 Через 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 правильно настроены? 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
snn_krs Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 Не понятно откуда 8 байт, если два 8-ми битных регистра. Поставьте вмесо F8, FF и должены включитьсявсе индикаторы. 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 18 сентября, 2017 Автор Поделиться Опубликовано 18 сентября, 2017 Я кажется понял свою ошибку, посмотрел внимательнее на схему и понял что не нужно никаких 64 бита передавать в регистр а всего 16. Первые байт отвечают за номер индикатора а второй значение на сегментах. Так что должно все получиться с SPI. Цитата Поставьте вмесо F8, FF и должены включитьсявсе индикаторы. Да действительно так и есть, загорелись все 4 индикатора, правда не цифрами а кракозябрами, осталось подобрать правильные коды символов 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 18 сентября, 2017 Автор Поделиться Опубликовано 18 сентября, 2017 В общем заработало в таком варианте #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 все логично. Что тогда не так? 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Yurkin2015 Опубликовано 18 сентября, 2017 Поделиться Опубликовано 18 сентября, 2017 Во-первых, у Вас настройка 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); 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 19 сентября, 2017 Автор Поделиться Опубликовано 19 сентября, 2017 (изменено) Уважаемый @Yurkin2015 вы абсолютно правы. Надо было мне сразу заглянуть в даташит на 74HC595 и тогда бы я увидел эту диаграмму. Поправил фронт и полярность в настройках GPIO. Ваш код действительно работает. Также он работает и в таком варианте когда сначала на линию LATCH_DIO устанавливаем 0, передаем данные по SPI c проверкой флагов и устанавливаем на LATCH_DIO = 1, так что теперь все логично и понятно. Спасибо. Осталось поиграть с SPI_NSS дабы не задействовать отдельную ногу под LATCH_DIO Изменено 19 сентября, 2017 пользователем le2x 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
le2x Опубликовано 19 сентября, 2017 Автор Поделиться Опубликовано 19 сентября, 2017 В общем понял что 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); } } 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.