esp-idf/components/hal/twai_hal_iram.c

110 lines
5.0 KiB
C
Raw Normal View History

// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include "hal/twai_hal.h"
/* ----------------------------- Event Handling ----------------------------- */
uint32_t twai_hal_decode_interrupt_events(twai_hal_context_t *hal_ctx)
{
uint32_t events = 0;
//Read interrupt, status
uint32_t interrupts = twai_ll_get_and_clear_intrs(hal_ctx->dev);
uint32_t status = twai_ll_get_status(hal_ctx->dev);
uint32_t tec = twai_ll_get_tec(hal_ctx->dev);
uint32_t rec = twai_ll_get_rec(hal_ctx->dev);
//Error Warning Interrupt set whenever Error or Bus Status bit changes
if (interrupts & TWAI_LL_INTR_EI) {
if (status & TWAI_LL_STATUS_BS) {
//Currently in BUS OFF state
if (status & TWAI_LL_STATUS_ES) { //EWL is exceeded, thus must have entered BUS OFF
twai_ll_set_mode(hal_ctx->dev, TWAI_MODE_LISTEN_ONLY); //Set to listen only to freeze tec and rec
events |= TWAI_HAL_EVENT_BUS_OFF;
TWAI_HAL_SET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_BUS_OFF);
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_RUNNING);
//Any TX would have been halted by entering bus off. Reset its flag
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
} else {
//Below EWL. Therefore TEC is counting down in bus recovery
events |= TWAI_HAL_EVENT_BUS_RECOV_PROGRESS;
}
} else {
//Not in BUS OFF
if (status & TWAI_LL_STATUS_ES) { //Just Exceeded EWL
events |= TWAI_HAL_EVENT_ABOVE_EWL;
TWAI_HAL_SET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
} else if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_RECOVERING) {
//Previously undergoing bus recovery. Thus means bus recovery complete
twai_ll_enter_reset_mode(hal_ctx->dev); //Enter reset mode to stop the peripheral
events |= TWAI_HAL_EVENT_BUS_RECOV_CPLT;
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_RECOVERING);
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_BUS_OFF);
} else { //Just went below EWL
events |= TWAI_HAL_EVENT_BELOW_EWL;
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
}
}
}
//Receive Interrupt set whenever RX FIFO is not empty
if (interrupts & TWAI_LL_INTR_RI) {
events |= TWAI_HAL_EVENT_RX_BUFF_FRAME;
}
//Transmit interrupt set whenever TX buffer becomes free
if (interrupts & TWAI_LL_INTR_TI) {
events |= TWAI_HAL_EVENT_TX_BUFF_FREE;
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
}
//Error Passive Interrupt on transition from error active to passive or vice versa
if (interrupts & TWAI_LL_INTR_EPI) {
if (tec >= TWAI_ERR_PASS_THRESH || rec >= TWAI_ERR_PASS_THRESH) {
events |= TWAI_HAL_EVENT_ERROR_PASSIVE;
TWAI_HAL_SET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
} else {
events |= TWAI_HAL_EVENT_ERROR_ACTIVE;
TWAI_HAL_RESET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
}
}
//Bus error interrupt triggered on a bus error (e.g. bit, ACK, stuff etc)
if (interrupts & TWAI_LL_INTR_BEI) {
twai_ll_clear_err_code_cap(hal_ctx->dev);
events |= TWAI_HAL_EVENT_BUS_ERR;
}
//Arbitration Lost Interrupt triggered on losing arbitration
if (interrupts & TWAI_LL_INTR_ALI) {
twai_ll_clear_arb_lost_cap(hal_ctx->dev);
events |= TWAI_HAL_EVENT_ARB_LOST;
}
return events;
}
void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame)
{
//Copy frame into tx buffer
twai_ll_set_tx_buffer(hal_ctx->dev, tx_frame);
//Hit the send command
if (tx_frame->self_reception) {
if (tx_frame->single_shot) {
twai_ll_set_cmd_self_rx_single_shot(hal_ctx->dev);
} else {
twai_ll_set_cmd_self_rx_request(hal_ctx->dev);
}
} else if (tx_frame->single_shot){
twai_ll_set_cmd_tx_single_shot(hal_ctx->dev);
} else {
twai_ll_set_cmd_tx(hal_ctx->dev);
}
TWAI_HAL_SET_FLAG(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
}