//----------------------------------------------------------------------------

//Класс поддержки последовательного регистра

//----------------------- Используемые ресурсы: ------------------------------

//Используются цепочка внешних регистров 74HC595, которые подключены
//к порту SPI1:
//линия тактирования SCLK подключена к SCK (PB3, используется remap)
//линия данных SDATA подключена к MOSI (PB5, используется remap)
//линия загрузки LOAD подключена к пину PB6
//линия разрешения выхода OE подключена к пину PB7
//Количество регистров в цепочке передается функции Init.

//----------------------------------------------------------------------------

#include "main.hpp"
#include "sreg.hpp"

//----------------------------------------------------------------------------
//----------------------------- Класс TSreg: ---------------------------------
//----------------------------------------------------------------------------

//---------------------------- Инициализация: --------------------------------

void TSreg::Init(uint8_t n)
{
  Regs = n;
  Pin_SCLK.Init(AF_PP_50M);
  Pin_SDATA.Init(AF_PP_50M);
  Pin_LOAD.Init(OUT_PP_50M, OUT_HI);
  Pin_OE.Init(OUT_OD_2M, OUT_HI);

  AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE | //JTAG disable
                AFIO_MAPR_SPI1_REMAP;           //remap выводов SPI1

  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //включение тактирования SPI1

  SPI1->CR1 =              //настройка SPI:
    SPI_CR1_CPHA     * 1 | //CPHA = 1
    SPI_CR1_CPOL     * 1 | //CPOL = 1
    SPI_CR1_MSTR     * 1 | //мастер
    SPI_CR1_BR_0     * 0 | //тактовая частота APB2 / 2
    SPI_CR1_SPE      * 1 | //разрешение SPI
    SPI_CR1_LSBFIRST * 0 | //MSB first
    SPI_CR1_SSI      * 1 | //мастер
    SPI_CR1_SSM      * 1 | //программное управление NSS
    SPI_CR1_RXONLY   * 0 | //full duplex
    SPI_CR1_DFF      * 0 | //8 bit data frame
    SPI_CR1_CRCNEXT  * 0 | //CRC не используется
    SPI_CR1_CRCEN    * 0 |
    SPI_CR1_BIDIOE   * 1 | //TX only
    SPI_CR1_BIDIMODE * 1;  //1-line mode
}

//----------------------- Запись байта через SPI1: ---------------------------

void TSreg::SpiWr(uint8_t d)
{
  //ожидание освобождения буфера:
  while(!(SPI1->SR & SPI_SR_TXE));
  SPI1->DR = d;
}

//-------------------------- Загрузка регистров: -----------------------------

void TSreg::Load(uint8_t *Value)
{
  Pin_LOAD = 0;
  //передача REGS байт:
  for(uint8_t n = 0; n < Regs; n++)
    SpiWr(Value[n]);
  //ожидание окончания передачи последнего байта:
  while(!(SPI1->SR & SPI_SR_TXE));
  while(SPI1->SR & SPI_SR_BSY);
  Pin_LOAD = 1;
}

//---------------- Разрешение/запрещение выходов регистров: ------------------

void TSreg::Enable(bool en)
{
  Pin_OE = !en;
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
