aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32f0/can.c
blob: 6ce9aad4e766477ca1feaaf4e06b476267632205 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * Serial over CAN emulation for STM32F042 boards.
 *
 *  Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
 *  This file may be distributed under the terms of the GNU GPLv3 license.
 *
 */

#include "stm32f0xx_hal.h"
#include <string.h>
#include "can.h"
#include "command.h" // encoder
#include "board/serial_irq.h" // serial_enable_tx_irq
#include "sched.h" // DECL_INIT
#include "log.h"

CAN_HandleTypeDef hcan;
CanTxMsgTypeDef    TxMessage;
CanRxMsgTypeDef    RxMessage;
static uint16_t MyCanId = 0;


void CanTransmit(uint32_t id, uint32_t dlc, uint8_t *pkt)
{
    memcpy(hcan.pTxMsg->Data, pkt, dlc);
    hcan.pTxMsg->StdId = id;
    hcan.pTxMsg->DLC = dlc;
    HAL_CAN_Transmit_IT(&hcan);
}

// Convert Unique 96-bit value into 48 bit representation
static void PackUuid(uint8_t* u)
{
    for(int i=0; i<SHORT_UUID_LEN; i++) {
        u[i] = *((uint8_t*)(STM32_UUID_ADDR+i)) ^
                *((uint8_t*)(STM32_UUID_ADDR+i+SHORT_UUID_LEN));
    }
}

static void CanUUIDResp(void)
{
    uint8_t short_uuid[SHORT_UUID_LEN];
    PackUuid(short_uuid);
    CanTransmit(PKT_ID_UUID_RESP, SHORT_UUID_LEN, short_uuid);
}

void CanInit(void)
{
    // Master reset
    //SET_BIT(CAN->MCR, CAN_MCR_RESET);

    hcan.Instance = CAN;
    hcan.Init.Prescaler = 12;
    hcan.Init.Mode = CAN_MODE_NORMAL;
    hcan.Init.SJW = CAN_SJW_1TQ;
    hcan.Init.BS1 = CAN_BS1_5TQ;
    hcan.Init.BS2 = CAN_BS2_2TQ;
    hcan.Init.TTCM = DISABLE;
    hcan.Init.ABOM = DISABLE;
    hcan.Init.AWUM = DISABLE;
    hcan.Init.NART = ENABLE;
    hcan.Init.RFLM = DISABLE;
    hcan.Init.TXFP = DISABLE;
    HAL_CAN_Init(&hcan);
    hcan.pTxMsg = &TxMessage;
    hcan.pRxMsg = &RxMessage;

    /*##-2- Configure the CAN Filter #######################################*/
    CAN_FilterConfTypeDef sFilterConfig;
    sFilterConfig.FilterNumber = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = PKT_ID_UUID<<5;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = PKT_ID_SET<<5;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

    /*##-3- Configure Transmission process #################################*/
    hcan.pTxMsg->ExtId = 0;
    HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);

    /* Request for port */
    CanUUIDResp();
}
DECL_INIT(CanInit);

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* h) {
    int i;

    if(!MyCanId) { // If serial not assigned yet
        if(h->pRxMsg->StdId == PKT_ID_UUID && h->pRxMsg->DLC == 0) {
            // Just inform host about my UUID
            CanUUIDResp();
        } else if (h->pRxMsg->StdId == PKT_ID_SET) {
            // compare my UUID with packet to check if this packet mine
            uint8_t short_uuid[SHORT_UUID_LEN];
            PackUuid(short_uuid);
            if (memcmp(&(h->pRxMsg->Data[2]), short_uuid,
                    SHORT_UUID_LEN) == 0) {
                memcpy(&MyCanId, h->pRxMsg->Data, sizeof(uint16_t));
                CAN_FilterConfTypeDef sFilterConfig;
                sFilterConfig.FilterNumber = 0;
                sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
                sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
                // Personal ID
                sFilterConfig.FilterIdHigh = MyCanId<<5;
                sFilterConfig.FilterIdLow = 0x0000;
                // Catch reset command
                sFilterConfig.FilterMaskIdHigh = PKT_ID_UUID<<5;
                sFilterConfig.FilterMaskIdLow = 0x0000;
                sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
                sFilterConfig.FilterActivation = ENABLE;
                // Disable 'set address' filter and enable only my packets
                HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
            }
        }
    } else {
        if(h->pRxMsg->StdId == MyCanId) {
            if(h->pRxMsg->DLC == 0) {
                // empty packet == ping request
                hcan.pTxMsg->StdId = MyCanId+1;
                hcan.pTxMsg->DLC = 0;
                HAL_CAN_Transmit_IT(&hcan);
            } else {
                for(i=0; i < h->pRxMsg->DLC; i++ ) {
                    serial_rx_byte(h->pRxMsg->Data[i]);
                }
            }
        } else if (h->pRxMsg->StdId == PKT_ID_UUID && h->pRxMsg->DLC > 0) {
            if (memcmp(&(h->pRxMsg->Data), &MyCanId, 2) == 0) {
                // Reset from host
                NVIC_SystemReset();
            }
        }
    }
    HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
}

void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *h)
{
    // Overrun handling - drop damaged packet
    HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
}

/**
  * @brief This function handles HDMI-CEC and CAN global interrupts /
  *  HDMI-CEC wake-up interrupt through EXTI line 27.
  */
void CEC_CAN_IRQHandler(void)
{
    HAL_CAN_IRQHandler(&hcan);
}

void
serial_enable_tx_irq(void)
{
    if(MyCanId == 0)
        // Serial port not initialized
        return;

    int i=0;
    for (;i<8;)
    {
        if(serial_get_tx_byte(&(hcan.pTxMsg->Data[i])) == -1) {
            break;
        }
        i++;
    }
    if (i>0) {
        hcan.pTxMsg->StdId = MyCanId+1;
        hcan.pTxMsg->DLC = i;
        HAL_CAN_Transmit_IT(&hcan);
    }
}

void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
{
    // if we still have some data to transmit
    serial_enable_tx_irq();
}

/*
 * @brief CAN MSP Initialization
 * @param h: CAN handle pointer
 * @retval None
 */
void HAL_CAN_MspInit(CAN_HandleTypeDef* h)
{

    __HAL_REMAP_PIN_ENABLE(HAL_REMAP_PA11_PA12);

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(h->Instance==CAN)
    {
        /* Peripheral clock enable */
        __HAL_RCC_CAN1_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**CAN GPIO Configuration
        PA11     ------> CAN_RX
        PA12     ------> CAN_TX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF4_CAN;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* CAN interrupt Init */
        HAL_NVIC_SetPriority(CEC_CAN_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(CEC_CAN_IRQn);
    }
}