Easyelectronics.ru

Электроника для всех
Текущее время: 23 май 2022, 01:06

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/5шт. два слоя. $5/5шт. четыре слоя
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: STM8 как ведомое устройство SPI (SPL)
СообщениеДобавлено: 30 янв 2021, 15:17 
Здравствуйте!

Зарегистрирован: 30 янв 2021, 15:01
Сообщения: 2
Всем привет, домучил МК (stm8s003f3p6), Удалось установить стабильную качественную связь, даже почти "аппаратно".

Так как аппаратного NSS почему-то нету (либо я что-то делал не так), и это писали на большинстве зарубежных форумах, в том числе и про 32 камни, было реализовано внешнее прерывание на ногу которую обозначают в "даташитах" NSS (я думаю можно использовать любую). Прерывание настраивается на срабатывание по фронтам (переходам с высокого на низкий уровень и наоборот).

Код:
static void EXTI_Config(void)
{
  EXTI_DeInit();
  GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_IT); // настраиваем как вход с подтяжкой к питанию
  EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA, EXTI_SENSITIVITY_RISE_FALL); //прерывание по фронтам
}


В функции прерывания пишем обработчик, который в зависимости от фронта будет включать или выключать SPI:

Код:
INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3)
{
  disableInterrupts();
  if (!System_SPI_NSS) //смотрим наш статус (при пуске контроллера тут лежит FALSE)
//этот флаг делаем сами, но можно и по другому реализовать, наверно
  {
    nop(); // можно убрать
    System_SPI_NSS = TRUE;
    SPI_NSSInternalSoftwareCmd(DISABLE); // ключевая функция благодаря которой все работает
    SPI_Cmd(ENABLE); //включаем SPI
  }
  else
  {
    nop(); // можно убрать
    System_SPI_NSS = FALSE;
    SPI_NSSInternalSoftwareCmd(ENABLE);
    SPI_Cmd(DISABLE);
  }
  enableInterrupts();
}


Код инициализации SPI:

Код:
static void SPI_Config(void)
{
  SPI_DeInit();
  SPI_Init(SPI_FIRSTBIT_MSB,
           SPI_BAUDRATEPRESCALER_2,
           SPI_MODE_SLAVE,
           SPI_CLOCKPOLARITY_LOW,
           SPI_CLOCKPHASE_1EDGE,
           SPI_DATADIRECTION_2LINES_FULLDUPLEX,
           SPI_NSS_SOFT,
           0x07);
  SPI_ITConfig(SPI_IT_RXNE, ENABLE);
  SPI_ITConfig(SPI_IT_TXE, ENABLE);
  SPI_NSSInternalSoftwareCmd(ENABLE);
  //SPI_Cmd(ENABLE);
}


А в обработчике прерывания SPI просматриваем статусы буферов отправки и приема, и уже относительно этого производим чтение или запись:

Код:
INTERRUPT_HANDLER(SPI_IRQHandler, 10)
{
  disableInterrupts();
  if (SPI_GetFlagStatus(SPI_FLAG_RXNE))
  {
    system_buff_mb_msg_rx[0] = SPI_ReceiveData();
  }
 
  if (SPI_GetFlagStatus(SPI_FLAG_TXE))
  {
    SPI_SendData(system_buff_mb_msg_rx[0]);
  }
  enableInterrupts();
}


Весь код целиком:

Код:
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"

/* Private defines -----------------------------------------------------------*/
#define TIM4_PERIOD 124
#define USER_TIME_CYCLE 10

unsigned int System_plc_time = USER_TIME_CYCLE;
bool System_SPI_NSS = FALSE;
uint8_t system_buff_mb_msg_rx[10];

/* Private function prototypes -----------------------------------------------*/
static void CLK_Config(void);
static void TIM4_Config(void);
static void SPI_Config(void);
static void EXTI_Config(void);

/* Private functions ---------------------------------------------------------*/
static void CLK_Config(void)
{
  CLK_DeInit();
  CLK_HSICmd(ENABLE);
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
  CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
  //CLK_CCOConfig(CLK_OUTPUT_MASTER);
}

static void TIM4_Config(void)
{
  TIM4_DeInit();
  TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD);
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
  TIM4_Cmd(ENABLE);
  TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
}

static void SPI_Config(void)
{
  SPI_DeInit();
  SPI_Init(SPI_FIRSTBIT_MSB,
           SPI_BAUDRATEPRESCALER_2,
           SPI_MODE_SLAVE,
           SPI_CLOCKPOLARITY_LOW,
           SPI_CLOCKPHASE_1EDGE,
           SPI_DATADIRECTION_2LINES_FULLDUPLEX,
           SPI_NSS_SOFT,
           0x07);
  SPI_ITConfig(SPI_IT_RXNE, ENABLE);
  SPI_ITConfig(SPI_IT_TXE, ENABLE);
  SPI_NSSInternalSoftwareCmd(ENABLE);
  //SPI_Cmd(ENABLE);
}

static void EXTI_Config(void)
{
  EXTI_DeInit();
  GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_IT);
  EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA, EXTI_SENSITIVITY_RISE_FALL);
}

INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
{
   disableInterrupts();
   System_plc_time--;
   if (System_plc_time > USER_TIME_CYCLE)
   {
     System_plc_time = USER_TIME_CYCLE;
   }
   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
   enableInterrupts();
}

INTERRUPT_HANDLER(SPI_IRQHandler, 10)
{
  disableInterrupts();
  if (SPI_GetFlagStatus(SPI_FLAG_RXNE))
  {
    system_buff_mb_msg_rx[0] = SPI_ReceiveData();
  }
 
  if (SPI_GetFlagStatus(SPI_FLAG_TXE))
  {
    SPI_SendData(system_buff_mb_msg_rx[0]);
  }
  enableInterrupts();
}

INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3)
{
  disableInterrupts();
  if (!System_SPI_NSS)
  {
    nop();
    System_SPI_NSS = TRUE;
    SPI_NSSInternalSoftwareCmd(DISABLE);
    SPI_Cmd(ENABLE);
  }
  else
  {
    nop();
    System_SPI_NSS = FALSE;
    SPI_NSSInternalSoftwareCmd(ENABLE);
    SPI_Cmd(DISABLE);
  }
  enableInterrupts();
}

void main(void)
{
  CLK_Config();
  TIM4_Config();
  SPI_Config();
  EXTI_Config();
  enableInterrupts();
 
  /* Infinite loop */
  while (1)
  {   
    if(!System_plc_time)
    {
      System_plc_time = USER_TIME_CYCLE;
    }
  }
 
}


#ifdef USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval : None
  */
void assert_failed(u8* file, u32 line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif



В данном случае пример реализует прием и передачу одного байта, "эхо", что принял, то и отправляет.
Тестировал с одним ведомым камнем пока. Ведущий RPI zero W.
Частота тактирования: 8МГц
Длина линии: 20см (имеется 3 соединения)
при прокладке линии NSS рядом с линиями данных и тактирования, возникает помеха, приходят недостоверные данные. Тактовая линия на линии данных не влияет. Частота опроса ведомого была 1мс. В дальнейшем планируется без задержек, но ведомых будет много, минимум 4 штуки.
Для устранения "помех" просто провод NSS убирал в сторону.
Так что при разводке плат в данном случае я бы линию выбора ведомого устройства прокладывал дальше от линий данных и тактирования. В интернете есть рекомендации по разводке линий данных. Советую изучить.

Ссылка на эстэшные (ST) рекомендации по разводке:
https://www.st.com/resource/en/application_note/dm00403849-layout-recommendations-for-the-design-of-boards-with-st25r3911bst25r391x-devices-stmicroelectronics.pdf


Вложения:
Комментарий к файлу: В прошлый раз не тот файл прикрепил, прошу прощения
main.c [3.41 Кб]
Скачиваний: 126
Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ 1 сообщение ] 


Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB