Нет вообще . Там нет SYS_Delay вообще в коде дисплея.
- Подпись автора
By Admin
USMI |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » USMI » MCU, SoC, CPU Микроконтроллеры » Подключение разной периферии к JL SoC. SPI/I2C/I2S/PWM/UART/GPIO...
Нет вообще . Там нет SYS_Delay вообще в коде дисплея.
By Admin
Интересно что при проигрывании музыки с флешки постоянно обновляется 3 строки и никаких щелчков. При регулировке громкости только одна строка обновляется и щелчки идут. Может оно просто чаще обновляется при изменении громкости.
Не. при громкости тоже косяков нет. Там вроде как два вида задержак, - если ты делаешь задержки таймером #1 то он привязан к проигрыванию музыки.
А стандартные дисплеи не используют задержки таймером. Ну там и spi шина вроде как до 100 MHz.
By Admin
Here, I attached an OLED display with an I2C bus to the AC6925A
hi.
Which sdk version did you use to write this code and where did you write the code?
I'm using the "AC692x_SDK_release_V2.6.3" SDK, where I've disabled its stock LCD driver (everything under apps/cpu/ui/lcd except lcd_disp.c) and put my own code in place of it.
So, there's the code that uses software bit-banged I2C interface (hardcoded to PB0/PB1 in my case):
Код:#include "sdk_cfg.h" #include "common.h" #include "hw_cpu.h" #include "uicon/dc_showres.h" /* UI_LCD_INFO, LCD_INFO */ #include "uicon/menu.h" /* language definitions for font_init_api */ #include "uicon_api.h" /* uicon_init_api */ #include "font_api.h" /* font_init_api */ #if LCD_128X64_EN #define DISP_I2C_ADDR 0x3C #define DISP_WIDTH 128 #define DISP_HEIGHT 64 #define DISP_PAGES (DISP_HEIGHT/8) /* Display buffer */ static u8 disp_buff[DISP_PAGES][DISP_WIDTH]; /* Currently-displayed buffer */ static u8 cdisp_buff[DISP_PAGES][DISP_WIDTH]; /* Is the display attached? */ static u8 disp_available; /*----------------------------------------------------------*/ static void si2c_init(void) { /* PB0 = SCL, PB1 = SDA */ JL_PORTB->OUT &= ~(3<<0); JL_PORTB->DIR |= (3<<0); JL_PORTB->DIE |= (3<<0); JL_PORTB->PU |= (3<<0); JL_PORTB->PD &= ~(3<<0); } static void si2c_start(void) { /* generate a start condition */ JL_PORTB->DIR &= ~(1<<1); delay(10); JL_PORTB->DIR &= ~(1<<0); delay(10); } static void si2c_stop(void) { /* generate a stop condition */ JL_PORTB->DIR |= (1<<0); delay(10); JL_PORTB->DIR |= (1<<1); delay(10); } static int si2c_sendb(u8 val) { int ack; for (int i = 0; i < 8; i++) { if (val & 0x80) JL_PORTB->DIR |= (1<<1); else JL_PORTB->DIR &= ~(1<<1); val <<= 1; delay(10); JL_PORTB->DIR |= (1<<0); delay(10); JL_PORTB->DIR &= ~(1<<0); } JL_PORTB->DIR |= (1<<1); delay(10); JL_PORTB->DIR |= (1<<0); delay(10); ack = (JL_PORTB->IN & (1<<1)) ? 0 : 1; JL_PORTB->DIR &= ~(1<<0); JL_PORTB->DIR &= ~(1<<1); return ack; } /*----------------------------------------------------------*/ /* * Send commands and data to the display controller. */ static int disp_send(const u8 *cmd, int cmdlen, const u8 *data, int datalen) { int ack; si2c_start(); ack = si2c_sendb(DISP_I2C_ADDR << 1); if (ack) { /* Send commands */ if (cmdlen > 0) { if (datalen > 0) { /* as separate command tokens */ while (cmdlen--) { si2c_sendb(0x80); si2c_sendb(*cmd++); } } else { /* as a single bulk */ si2c_sendb(0x00); while (cmdlen--) { si2c_sendb(*cmd++); } } } /* Send data */ if (datalen > 0) { /* as a single bulk */ si2c_sendb(0x40); while (datalen--) { si2c_sendb(*data++); } } } si2c_stop(); return ack; } static int disp_present(int scol, int ecol, int srow, int erow) { int ack; for (int page = srow; page <= erow; page++) { /* Send the row to the display */ u8 cmd[3] = { 0x00 + (scol & 0xF), /* Column position, low */ 0x10 + (scol >> 4), /* Column position, high */ 0xB0 + page /* Page index */ }; ack = disp_send(cmd, sizeof cmd, &disp_buff[page][scol], ecol-scol+1); /* Update the 'currently displayed' buffer, too */ memcpy(&cdisp_buff[page][scol], &disp_buff[page][scol], ecol-scol+1); if (!ack) break; } return ack; } static void disp_setup(void) { int ack; static const u8 init_cmds[] = { 0xAE, /* display off */ 0xA8,0x3F, /* mux ratio = 64 */ 0xD3,0x00, /* display offset = 0 */ 0x40, /* display start line = 0 */ 0xA1, /* reversed segment remap */ 0xC8, /* reversed COM scan direction */ 0xDA,0x12, /* COM pins config - no left/right swap - interlaced mode */ 0x81,0x7F, /* contrast control */ 0xA4, /* display CGRAM contents */ 0xA6, /* normal display */ 0xD5,0x80, /* osc frequency '8', clock divider '0' */ 0x8D,0x14, /* en charge pump regulator */ 0xAF, /* display on */ }; ack = disp_send(init_cmds, sizeof init_cmds, NULL, 0); if (ack) { /* Load the full contents of the display buffer into the display */ disp_present(0, DISP_WIDTH-1, 0, DISP_PAGES-1); /* We've got a display now */ disp_available = 1; } } static void disp_init(void) { si2c_init(); disp_setup(); } static void disp_update(void) { if (!disp_available) { /* Display is not available yet. Try to reinit it. */ disp_setup(); /* The display will be loaded with the full display buffer contents on init * so there is no need to do stuff below */ return; } for (int page = 0; page < DISP_PAGES; page++) { int scol, ecol; /* Find the first changed column */ for (scol = 0; scol < DISP_WIDTH; scol++) { if (disp_buff[page][scol] != cdisp_buff[page][scol]) break; } /* Find the last changed column */ for (ecol = DISP_WIDTH-1; ecol >= scol; ecol--) { if (disp_buff[page][ecol] != cdisp_buff[page][ecol]) break; } if (scol <= ecol) { /* Load the changed area into the display. */ int ack = disp_present(scol, ecol, page, page); if (!ack) { /* Maybe the display has been disconnected? */ disp_available = 0; break; } } } } /*----------------------------------------------------------*/ /* * Clear a range of complete pages */ void lcd_clear_area(u8 top, u8 bottom) { for (int page = top; page < bottom; page++) { memset(&disp_buff[page], 0, DISP_WIDTH); } } /* * Same as lcd_clear_area, but it updates the display too. */ void lcd_clear_area_with_draw(u8 top, u8 bottom) { lcd_clear_area(top, bottom); disp_update(); } /* * Clear a section of the display buffer */ void lcd_clear_area_rect(u8 top, u8 bottom, u8 left, u8 right) { for (int page = top; page < bottom; page++) { memset(&disp_buff[page][left], 0, right - left); } } /* * Invert a range of complete pages */ u32 lcd_TurnPixelReverse_Page(u8 start, u8 count) { for (int page = start; count > 0; count--, page++) { for (int x = 0; x < DISP_WIDTH; x++) disp_buff[page][x] ^= 0xff; } return TRUE; } /* * Invert a section of the display buffer */ u32 lcd_TurnPixelReverse_Rect(u8 left, u8 top, u8 right, u8 bottom) { for (int page = top; page <= bottom; page++) { for (int x = left; x <= right; x++) disp_buff[page][x] ^= 0xff; } return TRUE; } static const UI_LCD_IO ui_lcd_io = { .lcd_clear_area_callback = lcd_clear_area, .lcd_clear_area_with_draw_callback = lcd_clear_area_with_draw, .lcd_clear_area_rect_callback = lcd_clear_area_rect, .lcd_TurnPixelReverse_Page_callback = lcd_TurnPixelReverse_Page, .lcd_TurnPixelReverse_Rect_callback = lcd_TurnPixelReverse_Rect, }; const LCD_INFO lcd_info = { .ui_lcd_callback = (void *)&ui_lcd_io, .lcd_width = DISP_WIDTH, .lcd_height = DISP_HEIGHT, .lcd_buff = (void *)disp_buff, }; /*----------------------------------------------------------*/ /* * Display the buffer contents on the screen */ void draw_lcd_buf(void) { disp_update(); } /* * Clear the display buffer */ void lcd_clear(void) { memset(disp_buff, 0, sizeof disp_buff); } /* * Initialize the display */ void lcd_init(void) { if (!uicon_init_api()) return; if (!font_init_api(Russian)) return; disp_init(); lcd_clear(); } #endif // LCD_128X64_EN
And here's the code that uses a hardware I2C interface, with an interrupt-driven approach (so it doesn't block Timer0 when updating the display, meaning that it now lacks a partial update feature - a whole display buffer is sent every time):
Код:#include "sdk_cfg.h" #include "common.h" #include "hw_cpu.h" #include "cpu/irq_api.h" #include "cpu/clock_api.h" #include "uicon/dc_showres.h" /* UI_LCD_INFO, LCD_INFO */ #include "uicon/menu.h" /* language definitions for font_init_api */ #include "uicon_api.h" /* uicon_init_api */ #include "font_api.h" /* font_init_api */ /*---------------------------------------------------------------------------*/ #if LCD_128X64_EN #define DISP_I2C_ADDR 0x3C #define DISP_WIDTH 128 #define DISP_HEIGHT 64 #define DISP_PAGES (DISP_HEIGHT/8) static u8 disp_buff[DISP_PAGES][DISP_WIDTH]; static u8 disp_cur_row, disp_cur_col, disp_end_col; static u8 disp_state, disp_ongoing; static u8 disp_cmdcnt, disp_cmdbuff[4]; enum { DISP_STATE_START, DISP_STATE_CMD_TOKEN, DISP_STATE_CMD_VAL, DISP_STATE_DATA_TOKEN, DISP_STATE_DATA_VAL, DISP_STATE_STOP, }; static void disp_transfer_main(void); static void disp_transfer_error(void); static void disp_transfer_end(void); /*----------------------------------------------------------*/ /* send a start condition followed by an address byte */ static void hwiic_startb(u8 val) { JL_IIC->BUF = val; JL_IIC->CON0 = (JL_IIC->CON0 & ~(1<<3)) | (1<<5)|(1<<2); } /* send a data byte */ static void hwiic_sendb(u8 val) { JL_IIC->BUF = val; JL_IIC->CON0 = (JL_IIC->CON0 & ~(1<<3)) | (1<<2); } /* send a stop condition */ static void hwiic_stop(void) { JL_IIC->CON0 |= (1<<4)|(1<<2); } /* get received acknowledge value */ static int hwiic_rxack(void) { return (JL_IIC->CON0 & (1<<7)) ? 0 : 1; } /* poll the interrupt flag */ static void hwiic_poll_int(void) { while (!(JL_IIC->CON0 & (1<<15))); JL_IIC->CON0 |= (1<<14); } /* poll the END flag */ static void hwiic_poll_end(void) { while (!(JL_IIC->CON0 & (1<<13))); JL_IIC->CON0 |= (1<<12); } /* send a start condition and an address byte (blocking) */ static int hwiic_p_startb(u8 val) { hwiic_startb(val); hwiic_poll_int(); return hwiic_rxack(); } /* send a data byte (blocking) */ static int hwiic_p_sendb(u8 val) { hwiic_sendb(val); hwiic_poll_int(); return hwiic_rxack(); } /* send a stop condition (blocking) */ static void hwiic_p_stop(void) { hwiic_stop(); hwiic_poll_end(); } static void hwiic_irq_handler(void) { if (JL_IIC->CON0 & (1<<15)) { /* main interrupt */ JL_IIC->CON0 |= (1<<14); if (hwiic_rxack()) { /* continue with the transfer */ disp_transfer_main(); } else { /* something went wrong */ disp_transfer_error(); } } if (JL_IIC->CON0 & (1<<13)) { /* stop condition */ JL_IIC->CON0 |= (1<<12); disp_transfer_end(); } } IRQ_REGISTER(IRQ_IIC_IDX, hwiic_irq_handler); static void hwiic_pin_init(int map) { switch (map) { #if 0 case 0: /* SCL = USBDP, SDA = USBDM */ JL_USB->IO_CON0 = (1<<11) /* GPIO mode */ | (3<<9) /* DIE */ | (0<<8) /* slew rate */ | (0<<6) /* PU */ | (0<<4) /* PD */ | (3<<2) /* DIR */ | (0<<0); /* OUT */ break; #endif case 1: /* SCL = PC4, SDA = PC5 */ JL_PORTC->DIR |= (3<<4); JL_PORTC->DIE |= (3<<4); JL_PORTC->PU |= (3<<4); JL_PORTC->PD &= ~(3<<4); break; case 2: /* SCL = PC1, SDA = PC2 */ JL_PORTC->DIR |= (3<<1); JL_PORTC->DIE |= (3<<1); JL_PORTC->PU |= (3<<1); JL_PORTC->PD &= ~(3<<1); break; case 3: /* SCL = PA5, SDA = PA6 */ JL_PORTA->DIR |= (3<<5); JL_PORTA->DIE |= (3<<5); JL_PORTA->PU |= (3<<5); JL_PORTA->PD &= ~(3<<5); break; default: /* invalid */ return; } /* set up appropriate pinmux setting */ JL_IOMAP->CON1 = (JL_IOMAP->CON1 & ~(3<<18)) | (map<<18); } static void hwiic_set_speed(int freq) { u32 srcfreq = clock_get_lsb_freq(); JL_IIC->BAUD = (srcfreq / freq / 3) - 1; } static void hwiic_init(void) { /* initialize the pins */ hwiic_pin_init(1); /* clear interrupt flags */ JL_IIC->CON0 = (1<<14)|(1<<12); /* set the clock speed */ hwiic_set_speed(2000000); // 2 MHz! /* filtered input; enable */ JL_IIC->CON0 = (1<<9) | (1<<0); /* attach the interrupt handler */ IRQ_REQUEST(IRQ_IIC_IDX, hwiic_irq_handler); } /*----------------------------------------------------------*/ static int disp_write(int dc, const void *data, int size) { const u8 *pdata = data; int ack = hwiic_p_startb(DISP_I2C_ADDR << 1); if (ack) { ack = hwiic_p_sendb(dc ? 0x40 : 0x00); while (ack && size--) { ack = hwiic_p_sendb(*pdata++); } } hwiic_p_stop(); return ack; } static void disp_transfer_main(void) { switch (disp_state) { case DISP_STATE_START: /* begin the transfer */ hwiic_startb(DISP_I2C_ADDR << 1); /* send the commands first */ disp_state = DISP_STATE_CMD_TOKEN; break; case DISP_STATE_CMD_TOKEN: /* send the command token */ hwiic_sendb(0x80); /* send a single command byte */ /* and then the command byte itself. */ disp_state = DISP_STATE_CMD_VAL; break; case DISP_STATE_CMD_VAL: /* send the command byte */ hwiic_sendb(disp_cmdbuff[--disp_cmdcnt]); /* then either a next command byte or move on to sending data. */ disp_state = disp_cmdcnt == 0 ? DISP_STATE_DATA_TOKEN : DISP_STATE_CMD_TOKEN; break; case DISP_STATE_DATA_TOKEN: /* send the data token */ hwiic_sendb(0x40); /* from now on we'll transfer data bytes only */ /* now send data */ disp_state = DISP_STATE_DATA_VAL; break; case DISP_STATE_DATA_VAL: /* send the data byte */ hwiic_sendb(disp_buff[disp_cur_row][disp_cur_col]); if (disp_cur_col == disp_end_col) { /* we're done */ disp_state = DISP_STATE_STOP; } else { /* next column */ disp_cur_col++; } break; case DISP_STATE_STOP: /* done transferring, send a stop condition */ hwiic_stop(); break; } } static void disp_transfer_error(void) { /* stop the transfer prematurely */ hwiic_stop(); disp_ongoing = 0; } static void disp_transfer_start(void) { if (!disp_ongoing) { /* that's a first transfer */ disp_cur_row = 0; } else { /* next row */ disp_cur_row++; if (disp_cur_row >= DISP_PAGES) { /* no more rows to send - we're done. */ disp_ongoing = 0; return; } } /* just send the whole row */ disp_cur_col = 0; disp_end_col = DISP_WIDTH - 1; /* commands to set the appropriate position */ disp_cmdbuff[0] = 0x00 | (disp_cur_col & 0xf); disp_cmdbuff[1] = 0x10 | (disp_cur_col >> 4); disp_cmdbuff[2] = 0xB0 | disp_cur_row; disp_cmdcnt = 3; /* let's go! */ disp_state = DISP_STATE_START; disp_transfer_main(); if (!disp_ongoing) { disp_ongoing = 1; /* enable interrupts */ JL_IIC->CON0 |= (1<<10)|(1<<8); } } static void disp_transfer_end(void) { if (disp_ongoing) { /* continue transferring */ disp_transfer_start(); } if (!disp_ongoing) { /* we're done now. stop receiving interrupts! */ JL_IIC->CON0 &= ~((1<<10)|(1<<8)); } } static void disp_init(void) { static const u8 init_data[] = { 0xAE, /* display off */ 0xA8,0x3F, /* mux ratio = 64 */ 0xD3,0x00, /* display offset = 0 */ 0x40, /* display start line = 0 */ 0xA1, /* reversed segment remap */ 0xC8, /* reversed COM scan direction */ 0xDA,0x12, /* COM pins config - no left/right swap - interlaced mode */ 0x81,0x7F, /* contrast control */ 0xA4, /* display CGRAM contents */ 0xA6, /* normal display */ 0xD5,0x80, /* osc frequency '8', clock divider '0' */ 0x8D,0x14, /* en charge pump regulator */ 0xAF, /* display on */ }; disp_write(0, init_data, sizeof init_data); } static void disp_update(void) { if (!disp_ongoing) { /* start a first transfer */ disp_transfer_start(); } } /*----------------------------------------------------------*/ /* * Clear a range of complete pages */ void lcd_clear_area(u8 top, u8 bottom) { for (int page = top; page < bottom; page++) { memset(&disp_buff[page], 0, DISP_WIDTH); } } /* * Same as lcd_clear_area, but it updates the display too. */ void lcd_clear_area_with_draw(u8 top, u8 bottom) { lcd_clear_area(top, bottom); disp_update(); } /* * Clear a section of the display buffer */ void lcd_clear_area_rect(u8 top, u8 bottom, u8 left, u8 right) { for (int page = top; page < bottom; page++) { memset(&disp_buff[page][left], 0, right - left); } } /* * Invert a range of complete pages */ u32 lcd_TurnPixelReverse_Page(u8 start, u8 count) { for (int page = start; count > 0; count--, page++) { for (int x = 0; x < DISP_WIDTH; x++) { disp_buff[page][x] ^= 0xff; } } return TRUE; } /* * Invert a section of the display buffer */ u32 lcd_TurnPixelReverse_Rect(u8 left, u8 top, u8 right, u8 bottom) { for (int page = top; page <= bottom; page++) { for (int x = left; x <= right; x++) { disp_buff[page][x] ^= 0xff; } } return TRUE; } static const UI_LCD_IO ui_lcd_io = { .lcd_clear_area_callback = lcd_clear_area, .lcd_clear_area_with_draw_callback = lcd_clear_area_with_draw, .lcd_clear_area_rect_callback = lcd_clear_area_rect, .lcd_TurnPixelReverse_Page_callback = lcd_TurnPixelReverse_Page, .lcd_TurnPixelReverse_Rect_callback = lcd_TurnPixelReverse_Rect, }; const LCD_INFO lcd_info = { .ui_lcd_callback = (void *)&ui_lcd_io, .lcd_width = DISP_WIDTH, .lcd_height = DISP_HEIGHT, .lcd_buff = (void *)disp_buff, }; /*----------------------------------------------------------*/ /* * Display the buffer contents on the screen */ void draw_lcd_buf(void) { disp_update(); } /* * Clear the display buffer */ void lcd_clear(void) { memset(disp_buff, 0, sizeof disp_buff); } /* * Initialize the display */ void lcd_init(void) { /* initialize uicon library */ if (!uicon_init_api()) return; /* initialize font library */ if (!font_init_api(Russian)) return; /* initialize interface */ hwiic_init(); /* initialize display */ disp_init(); } #endif // LCD_128X64_EN
水Mizu-DEC JLtech since 22.06.2019
I'm using the "AC692x_SDK_release_V2.6.3" SDK, where I've disabled its stock LCD driver (everything under apps/cpu/ui/lcd except lcd_disp.c) and put my own code in place of it.
So, there's the code that uses software bit-banged I2C interface (hardcoded to PB0/PB1 in my case):
And here's the code that uses a hardware I2C interface, with an interrupt-driven approach (so it doesn't block Timer0 when updating the display, meaning that it now lacks a partial update feature - a whole display buffer is sent every time):
It worked.
But apparently sdk 2.6.3 is written for 8Mbit chips.
Therefore, it could not be programmed on the bt201 chip
It worked.
But apparently sdk 2.6.3 is written for 8Mbit chips.
Therefore, it could not be programmed on the bt201 chip
Wrong. SDK 2.6.3 for all 692 chips. U need just adapt sdk. Turn off some function and codecs (flac/wav/wma/m4a/).
By Admin
It worked.
But apparently sdk 2.6.3 is written for 8Mbit chips.
Therefore, it could not be programmed on the bt201 chip
You can consider removing the font library
错误的。适用于所有 692 芯片的 SDK 2.6.3。你只需要适配sdk。关闭一些功能和编解码器(flac/wav/wma/m4a/)。
Yes, turn off some features, such as notification sounds
You are right.
After compiling, the size of sdk.app is 667kbyte.
I did not understand exactly in which part of the project are these additional measures🤔
Не. при громкости тоже косяков нет. Там вроде как два вида задержак, - если ты делаешь задержки таймером #1 то он привязан к проигрыванию музыки.
А стандартные дисплеи не используют задержки таймером. Ну там и spi шина вроде как до 100 MHz.
The size went down. I even had to disable dts.
你好。
您使用哪个 sdk 版本编写此代码以及在哪里编写代码?
You can use clion, which is very convenient
می توانید از کلیون استفاده کنید که بسیار راحت است
I disabled the codecs, but there is no sound when playing with ufd or bluetooth.it's mute.
Have you enabled the "UI_ENABLE" and "LCD_128X64_EN" options in sdk_cfg.h?
If so, then you need to change the argument of the font_init_api function in lcd_init (i2c_oled.c) from font_init_api(Russian) to font_init_api(Chinese_Simplified), and then you need to add the "f_ascii_s.pix" file from the "ui_resource" directory to the isd_download command line, then make an empty file called "f_gb2312.tab" and a dummy "f_gb2312_s.pix" file consisting of 6 bytes: "10 00 00 00 00 00" - this way you don't have to include the original font files into the firmware (which are huge). Add these files in the command line too. Of course you shouldn't forget to add the "menu.res" and "ui_sty.sty" files too.
e.g.:
isd_download.exe -tonorflash -dev br21 -boot 0x2000 -div6 -wait 300 -f uboot.boot sdk.app bt_cfg.bin bt.mp3 music.mp3 linein.mp3 radio.mp3 pc.mp3 connect.mp3 disconnect.mp3 ring.mp3 warning.mp3 power_off.mp3 echo.mp3 record.mp3 ui_resource\menu.res ui_resource\ui_sty.sty ui_resource\f_ascii_s.pix f_gb2312_s.pix f_gb2312.tab - where the latter two are the dummy files, not original ones from ui_resource.
水Mizu-DEC JLtech since 22.06.2019
Набросал тут сдк под модуль bt201 -
AD_key EN, - all commands set.
FM radio (stereo ON) (допаяйте элементы антенны - на плате их нет)
BT/USB/TF/PC audio
LED
MP3/FLAC/SBC
Add "free key patch" - download to all chip. Key no matter.
----------------------------------------------------------
Что на данный момент не работает -
I2C дисплей. Вроде все сделал как нужно. Если оставить русский вместо китайского упрощенного - циклический ребут.
MUTE I/O not set yet.
Так же не проверил микрофон.
bt201-sdk download
Password - 1111
By Admin
Solara написал что работает. У меня по ходу жисплей дохлый.
By Admin
Вы здесь » USMI » MCU, SoC, CPU Микроконтроллеры » Подключение разной периферии к JL SoC. SPI/I2C/I2S/PWM/UART/GPIO...