/*================================================================ Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. Quectel Wireless Solution Proprietary and Confidential. =================================================================*/ /*================================================================= EDIT HISTORY FOR MODULE This section contains comments describing changes made to the module. Notice that changes are listed in reverse chronological order. WHEN WHO WHAT, WHERE, WHY ------------ ------- ------------------------------------------------------------------------------- =================================================================*/ #include #include #include #include "ql_api_osi.h" #include "ql_api_spi.h" #include "ql_log.h" #include "spi_demo.h" #include "ql_gpio.h" #include "ql_power.h" #define QL_SPI_DEMO_LOG_LEVEL QL_LOG_LEVEL_INFO #define QL_SPI_DEMO_LOG(msg, ...) QL_LOG(QL_SPI_DEMO_LOG_LEVEL, "ql_SPI_DEMO", msg, ##__VA_ARGS__) #define QL_SPI_DEMO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_SPI_DEMO", msg, ##__VA_ARGS__) /** * 使用SPI DMA注意事项: * 8910: * 1. SPI DMA POLLING和SPI DMA IRQ只支持8bit和16bit的数据传输,不支持32bit数据传输 * 2. 在使用16bit传输数据时,DMA实际使用的是32bit位宽,需要对输出数据插入一些无效数据,对输入数据去除无效数据, * 因此新增16bit dma api用于16bit情况下的读写,api包含ql_spi_write_16bit_dma、ql_spi_read_16bit_dma、 * ql_spi_write_read_16bit_dma,这部分代码在demo中开源,客户可自行优化,或直接使用 * 3. QL_SPI_16BIT_DMA置为1表示使用16bit DMA demo * 8850: * 1. SPI DMA POLLING和SPI DMA IRQ支持8bits、16bits和32bits的数据传输,但是传输的数据大小需要framesize对齐。 */ #define QL_SPI_16BIT_DMA 0 //16bit DMA demo #define QL_SPI_DEMO_LOW_POWER_USE 0 //0-not run in lower power mode;1-run in lower power mode ql_task_t spi_demo_task = NULL; ql_sem_t spi_demo_write; ql_sem_t spi_demo_read; int spi_power_lock = 0; #define QL_SPI_DEMO_WAIT_NONE 0 #define QL_SPI_DEMO_WAIT_WRITE 1 #define QL_SPI_DEMO_WAIT_READ 2 unsigned char spi_demo_wait_write_read = QL_SPI_DEMO_WAIT_NONE; #if 1 #define QL_CUR_SPI_PORT QL_SPI_PORT1 #define QL_CUR_SPI_CS_PIN QL_CUR_SPI1_CS_PIN #define QL_CUR_SPI_CS_FUNC QL_CUR_SPI1_CS_FUNC #define QL_CUR_SPI_CLK_PIN QL_CUR_SPI1_CLK_PIN #define QL_CUR_SPI_CLK_FUNC QL_CUR_SPI1_CLK_FUNC #define QL_CUR_SPI_DO_PIN QL_CUR_SPI1_DO_PIN #define QL_CUR_SPI_DO_FUNC QL_CUR_SPI1_DO_FUNC #define QL_CUR_SPI_DI_PIN QL_CUR_SPI1_DI_PIN #define QL_CUR_SPI_DI_FUNC QL_CUR_SPI1_DI_FUNC #else #define QL_CUR_SPI_PORT QL_SPI_PORT2 #define QL_CUR_SPI_CS_PIN QL_CUR_SPI2_CS_PIN #define QL_CUR_SPI_CS_FUNC QL_CUR_SPI2_CS_FUNC #define QL_CUR_SPI_CLK_PIN QL_CUR_SPI2_CLK_PIN #define QL_CUR_SPI_CLK_FUNC QL_CUR_SPI2_CLK_FUNC #define QL_CUR_SPI_DO_PIN QL_CUR_SPI2_DO_PIN #define QL_CUR_SPI_DO_FUNC QL_CUR_SPI2_DO_FUNC #define QL_CUR_SPI_DI_PIN QL_CUR_SPI2_DI_PIN #define QL_CUR_SPI_DI_FUNC QL_CUR_SPI2_DI_FUNC #endif #define QL_TYPE_SHIFT_8 8 uint32_t g_inbuf[QL_SPI_DMA_IRQ_SIZE/4] OSI_CACHE_LINE_ALIGNED; uint32_t g_outbuf[QL_SPI_DMA_IRQ_SIZE/4] OSI_CACHE_LINE_ALIGNED; void ql_spi_read_data_transform(unsigned char *buf, unsigned int len) { if(len%2 != 0 || len > QL_SPI_DMA_IRQ_SIZE/2) { QL_SPI_DEMO_LOG("invalid parm"); return; } for(int i = 0; i < len/2; i++) { buf[i*2] = (g_inbuf[i] >> QL_TYPE_SHIFT_8) & 0xFF; buf[i*2+1] = g_inbuf[i] & 0xFF; } } ql_errcode_spi_e ql_spi_write_16bit_dma(ql_spi_port_e port, unsigned char *buf, unsigned int len) { if(len%2 != 0 || len > QL_SPI_DMA_IRQ_SIZE/2) { QL_SPI_DEMO_LOG("invalid parm"); return QL_SPI_PARAM_DATA_ERROR; } unsigned short out_temp = 0; for(int i = 0; i < len/2; i++) { out_temp = buf[i*2]; g_outbuf[i] = (out_temp << QL_TYPE_SHIFT_8) + buf[i*2+1]; } return ql_spi_write(port, (unsigned char*)g_outbuf, len*2); } ql_errcode_spi_e ql_spi_read_16bit_dma(ql_spi_port_e port, unsigned char *buf, unsigned int len) { if(len%2 != 0 || len > QL_SPI_DMA_IRQ_SIZE/2) { QL_SPI_DEMO_LOG("invalid parm"); return QL_SPI_PARAM_DATA_ERROR; } return ql_spi_read(port, (unsigned char*)g_inbuf, len*2); } ql_errcode_spi_e ql_spi_write_read_16bit_dma(ql_spi_port_e port, unsigned char *inbuf, unsigned char *outbuf, unsigned int len) { if(len%2 != 0 || len > QL_SPI_DMA_IRQ_SIZE/2) { QL_SPI_DEMO_LOG("invalid parm"); return QL_SPI_PARAM_DATA_ERROR; } unsigned short out_temp = 0; for(int i = 0; i < len/2; i++) { out_temp = outbuf[i*2]; g_outbuf[i] = (out_temp << QL_TYPE_SHIFT_8) + outbuf[i*2+1]; } return ql_spi_write_read(port, (unsigned char*)g_inbuf, (unsigned char*)g_outbuf, len*2); } void ql_spi_flash_data_printf(unsigned char *data, int len) { int i = 0; int count_len = 256; int count = 0; int exit = 0; int write_len = 0; int pos = 0; unsigned char *str_data = (unsigned char *)malloc(len*2+64); if (str_data == NULL) { QL_SPI_DEMO_LOG("malloc err"); return ; } QL_SPI_DEMO_LOG("read len=%d", len); while ((exit == 0)) { if (len - count > 256) { count_len = 256; } else { count_len = len - count; exit = 1; } memset(str_data, 0, len*2+64); for (i=count; i 4 ? 1 : cmd_type + 1; data_mpu_pack(outdata, &outlen, 0X50, cmd_type); ql_spi_write(QL_CUR_SPI_PORT, outdata, 256); if(transmode == QL_SPI_DMA_IRQ) { ql_rtos_semaphore_wait(spi_demo_write, QL_WAIT_FOREVER); //tx_dma_done只是DMA完成了,但是SPI的FIFO还可能存在数据未发送,在进入慢时钟或clk频率较低时出现 ql_spi_get_tx_fifo_free(QL_CUR_SPI_PORT, &tx_free); QL_SPI_DEMO_LOG("tx_free=%d",tx_free); ql_delay_us((framesize+2)*(QL_SPI_FIFO_SIZE - tx_free)*1000000/spiclk); //恢复允许进入慢时钟 ql_spi_release_sys_clk(QL_CUR_SPI_PORT); ql_spi_flash_data_printf(outdata, outlen); } //ql_rtos_task_sleep_ms(10); //ql_spi_write_read(QL_CUR_SPI_PORT, outdata, indata, 256); ///////////////////////////////////// /////////////READ//////////////////// ///////////////////////////////////// if(transmode == QL_SPI_DMA_IRQ) { spi_demo_wait_write_read = QL_SPI_DEMO_WAIT_READ; //不允许进入慢时钟 ql_spi_request_sys_clk(QL_CUR_SPI_PORT); } ql_spi_read(QL_CUR_SPI_PORT, indata, 512); if(transmode == QL_SPI_DMA_IRQ) { ql_rtos_semaphore_wait(spi_demo_read, QL_WAIT_FOREVER); //恢复允许进入慢时钟 ql_spi_release_sys_clk(QL_CUR_SPI_PORT); ql_spi_flash_data_printf(indata, inlen); unsigned short sendLen = 0; data_decode_mpu(indata, 256, outdata, &sendLen); } #endif ql_rtos_task_sleep_ms(500); } ql_spi_release(QL_CUR_SPI_PORT); free(out_mal_data); free(in_mal_data); QL_SPI_EXIT: QL_SPI_DEMO_LOG("ql_rtos_task_delete"); err = ql_rtos_task_delete(NULL); if(err != QL_OSI_SUCCESS) { QL_SPI_DEMO_LOG("task deleted failed"); } } QlOSStatus ql_spi_demo_init(void) { QlOSStatus err = QL_OSI_SUCCESS; #if QL_SPI_DEMO_LOW_POWER_USE spi_power_lock = ql_lpm_wakelock_create("spi_irq", strlen("spi_irq")); #endif err = ql_rtos_task_create(&spi_demo_task, SPI_DEMO_TASK_STACK_SIZE, SPI_DEMO_TASK_PRIO, "ql_spi_demo", ql_spi_demo_task_pthread, NULL, SPI_DEMO_TASK_EVENT_CNT); if(err != QL_OSI_SUCCESS) { QL_SPI_DEMO_LOG("demo_task created failed"); return err; } return err; } uint16_t Full_Frame_Verifi(uint8_t *srcdata, uint16_t srcLen, uint16_t* frame_start) { uint16_t frame_len = 0; // 获取帧长度 uint8_t frame_flag = 0; //找到帧起始位 for(uint32_t i = 0; i < (srcLen - sizeof(frame_pack_t)) && 0 == frame_flag; i++) { if(0X5A == srcdata[i]) { frame_len = srcdata[i + FRAME_LEN_INDEX] + (srcdata[i + FRAME_LEN_INDEX + 1] << 8); if((i + frame_len + 1) < srcLen && (srcdata[i + frame_len - 2] + (srcdata[i + frame_len - 1] << 8) == crc16_modbus(srcdata + i, frame_len -2))) { frame_flag = 1; (*frame_start) = i; //QL_SPI_DEMO_LOG("cmd :%d %d %dxxxxxx len %d", frame_flag, *frame_start, i, frame_len); return frame_len; } } } return 0; } uint8_t data_mpu_pack(uint8_t* output, uint16_t* output_data_len, uint8_t cmd, uint8_t cmd_type) { frame_pack_t frame_tmp = {0}; frame_tmp.destination_addr = MCU_ADDR; frame_tmp.source_addr = MPU_ADDR; frame_tmp.frame_head = 0X5A; switch (cmd) { case 0X50: /* code */ frame_tmp.cmd = 0X50; switch (cmd_type) { case 0X01: frame_tmp.cmd_type = 0X01; break; case 0X02: frame_tmp.cmd_type = 0X02; break; case 0X03: frame_tmp.cmd_type = 0X03; break; default: break; } *output_data_len = sizeof(frame_pack_t); break; case 0X60: /* code */ frame_tmp.cmd = 0X60; switch (cmd_type) { case 0X01: frame_tmp.cmd_type = 0X01; break; case 0X02: frame_tmp.cmd_type = 0X02; break; case 0X03: frame_tmp.cmd_type = 0X03; break; default: break; } break; default: break; } frame_tmp.data_lenth = 2 + *output_data_len; memcpy(output, &frame_tmp, sizeof(frame_pack_t)); uint16_t crc16 = crc16_modbus(output, *output_data_len); output[(*output_data_len)++] = crc16 & 0XFF; output[(*output_data_len)++] = (crc16 >> 8) & 0XFF; return 0; } uint8_t data_decode_mpu(uint8_t *input_data, uint16_t input_data_len, uint8_t* output, uint16_t* output_data_len) { uint16_t frame_start = 0; // 帧起始位 uint16_t frame_len = 0; *output_data_len = 0; static frame_pack_t frame_tmp = {0}; frame_tmp.frame_head = 0X5A; frame_tmp.destination_addr = MPU_ADDR; frame_tmp.source_addr = MCU_ADDR; //frame_pack_t* frame_read_tmp; frame_len = Full_Frame_Verifi(input_data, input_data_len, &frame_start); //QL_SPI_DEMO_LOG("cmd :%d %dxxxxxx",frame_len, frame_start); if(0 == frame_len) return 1; else {} *output_data_len += sizeof(frame_pack_t); //QL_SPI_DEMO_LOG("cmd :%d %dxxxxxx",input_data[frame_start + FRAME_CMD_INDEX], frame_start); switch(input_data[frame_start + FRAME_CMD_INDEX]) { case 0X50: frame_tmp.cmd = 0X50; switch(input_data[frame_start + FRAME_CMD_TYPE_INDEX]) { case 0X01: QL_SPI_DEMO_LOG("cmd :0X01----"); break; case 0X02: QL_SPI_DEMO_LOG("cmd :0X02----"); break; case 0X03: QL_SPI_DEMO_LOG("cmd :0X03----"); break; default: break; } break; case 0X60: // switch(input_data[frame_start + FRAME_CMD_TYPE_INDEX]) { case 0X01: /// *output_data_len = 0; break; case 0X02: /// break; case 0X03: // break; case 0X04: // break; default: break; } *output_data_len = 0; return 0; break; default: break; } memcpy(output, &frame_tmp, sizeof(frame_pack_t)); //帧固定帧在此复制 uint16_t crc16 = crc16_modbus(output, *output_data_len); output[(*output_data_len)++] = crc16 & 0XFF; output[(*output_data_len)++] = (crc16 << 8) & 0XFF; return 0; } unsigned short crc16_modbus(unsigned char *pdata, int len) { int j = 0; int i = 0; uint16_t reg_crc = 0xffff; while (i < len ) { reg_crc ^= pdata[i]; i++; for (j = 0; j < 8; j++) { if ((reg_crc & 0x01) == 1) { reg_crc = (uint16_t)((reg_crc >> 1) ^ 0xa001); } else { reg_crc = (uint16_t)( reg_crc >> 1); } } } return reg_crc; }