1 | /**
|
2 | * @brief Configures LTC6803 SPI
|
3 | * @param None
|
4 | * @retval None
|
5 | */
|
6 | void LTC6803_Init(void)
|
7 | {
|
8 | GPIO_InitTypeDef GPIO_InitStructure;
|
9 | SPI_InitTypeDef SPI_InitStructure;
|
10 |
|
11 | SPI_I2S_DeInit(SPI2);
|
12 |
|
13 | /* Enable the LTC6803_CS clock */
|
14 | RCC_AHB1PeriphClockCmd(LTC6803_CS_GPIO_CLK, ENABLE);
|
15 | /* Configure the LTC6803_CS as output */
|
16 | GPIO_InitStructure.GPIO_Pin = LTC6803_CS_PIN;
|
17 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
18 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
19 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
20 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
21 | GPIO_Init(LTC6803_CS_GPIO_PORT, &GPIO_InitStructure);
|
22 | /* LTC6803_!CS as high (not active) */
|
23 | GPIO_WriteBit(LTC6803_CS_GPIO_PORT, LTC6803_CS_PIN, Bit_SET);
|
24 |
|
25 | /* Enable the LTC6803_SCLK clock */
|
26 | RCC_AHB1PeriphClockCmd(LTC6803_SCLK_GPIO_CLK, ENABLE);
|
27 | /* Configure the LTC6801_NSOUT as input */
|
28 | GPIO_InitStructure.GPIO_Pin = LTC6803_SCLK_PIN;
|
29 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
30 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
31 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
32 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
33 | GPIO_Init(LTC6803_SCLK_GPIO_PORT, &GPIO_InitStructure);
|
34 |
|
35 | /* Enable the LTC6803_DOUT (MISO) clock */
|
36 | RCC_AHB1PeriphClockCmd(LTC6803_DOUT_GPIO_CLK, ENABLE);
|
37 | /* Configure the LTC6803_DOUT (MISO) as SPI2 DOUT */
|
38 | GPIO_InitStructure.GPIO_Pin = LTC6803_DOUT_PIN;
|
39 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
40 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
41 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
|
42 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
43 | GPIO_Init(LTC6803_DOUT_GPIO_PORT, &GPIO_InitStructure);
|
44 |
|
45 | /* Enable the LTC6803_DIN (MOSI) clock */
|
46 | RCC_AHB1PeriphClockCmd(LTC6803_DIN_GPIO_CLK, ENABLE);
|
47 | /* Configure the LTC6803_DIN (MOSI) as SPI2 DIN */
|
48 | GPIO_InitStructure.GPIO_Pin = LTC6803_DIN_PIN;
|
49 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
50 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
51 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
|
52 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
53 | GPIO_Init(LTC6803_DIN_GPIO_PORT, &GPIO_InitStructure);
|
54 |
|
55 | /* Connect LTC6803 SPI pins to AF5 */
|
56 | GPIO_PinAFConfig(LTC6803_DIN_GPIO_PORT, LTC6803_DIN_PIN_SOURCE, GPIO_AF_SPI2);
|
57 | GPIO_PinAFConfig(LTC6803_SCLK_GPIO_PORT, LTC6803_SCLK_PIN_SOURCE, GPIO_AF_SPI2);
|
58 | GPIO_PinAFConfig(LTC6803_DOUT_GPIO_PORT, LTC6803_DOUT_PIN_SOURCE, GPIO_AF_SPI2);
|
59 |
|
60 | /* Enable the SPI2 clock */
|
61 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
|
62 |
|
63 | /* Configure the SPI2 bus */
|
64 | SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
65 | SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
|
66 | SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
|
67 | SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
|
68 | SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
|
69 | SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; // 42MHz/128 = 328kHz
|
70 | SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
|
71 | SPI_InitStructure.SPI_CRCPolynomial = 8;
|
72 | SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
|
73 |
|
74 | /* Initialize the SPI2 bus */
|
75 | SPI_Init(SPI2, &SPI_InitStructure);
|
76 | SPI_Cmd(SPI2, ENABLE);
|
77 |
|
78 | /* Calculates the table for PEC data */
|
79 | CRC8_Init();
|
80 | }
|
81 |
|
82 | /**
|
83 | * @brief Sends data through the SPI interface and return the data received
|
84 | * from the SPI bus.
|
85 | * @param data: data to send.
|
86 | * @retval The value of the received data.
|
87 | */
|
88 | uint8_t SPI2_SendReceive(uint8_t data)
|
89 | {
|
90 | /*!< Loop while DR register in not empty */
|
91 | while ((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
|
92 |
|
93 | /*!< Send data through the SPI2 peripheral */
|
94 | SPI2->DR = data;
|
95 |
|
96 | /*!< Wait to receive data */
|
97 | while ((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
|
98 |
|
99 | return SPI2->DR;
|
100 | }
|
101 |
|
102 | /**
|
103 | * @brief CRC8_Init calculates the CRC8 table for PEC calc
|
104 | * Cite: http://www.rajivchakravorty.com/source-code/uncertainty/multimedia-sim/html/crc8_8c.html
|
105 | * @param None
|
106 | * @retval None
|
107 | */
|
108 | static void CRC8_Init(void)
|
109 | {
|
110 | uint16_t i, j;
|
111 | uint8_t crc;
|
112 | for (i = 0; i < 256; i++)
|
113 | {
|
114 | crc = i;
|
115 | for (j = 0; j < 8; j ++)
|
116 | {
|
117 | crc = (crc << 1) ^ ((crc & 0x80) ? 0x07 : 0);
|
118 | }
|
119 | CRC8_Table[i] = crc & 0xFF;
|
120 | }
|
121 | }
|
122 |
|
123 | /**
|
124 | * @brief CalcPEC_Byte calculates the PEC for the given byte
|
125 | * @param Data: byte for which the PEC should be calculated
|
126 | * @retval calculated PEC byte
|
127 | */
|
128 | uint8_t CalcPEC_Byte(uint8_t Data)
|
129 | {
|
130 | /* Initialize PECbyte */
|
131 | uint8_t crc = 0x41;
|
132 | return CRC8_Table[(crc) ^ Data];
|
133 | }
|
134 |
|
135 | /**
|
136 | * @brief CalcPEC_Packet calculates the PEC for the data in LTC6803_RX
|
137 | * @param Len: number of bytes which are relevant in LTC6803_RX
|
138 | * @retval calculated PEC byte
|
139 | */
|
140 | uint8_t CalcPEC_Packet(uint8_t Len)
|
141 | {
|
142 | uint16_t i;
|
143 | /* Initialize PECbyte */
|
144 | uint8_t crc = 0x41;
|
145 | for (i = 0; i < Len; i++)
|
146 | {
|
147 | crc = CRC8_Table[(crc) ^ LTC6803_RX[i]];
|
148 | }
|
149 | return crc;
|
150 | }
|