Nâng cấp 32kbyte RAM cho arduino mega với ic UT62256CSCL-70LL

Mô tả dự án: 

Trong bài này, mình sẽ hướng dẫn các bạn nâng cấp 32kbyte RAM ngoài cho arduino mega sử dụng ic SRAM giá rê  UT62256CSCL-70LL.

Đọc ngay thôi, đừng bỏ lỡ @@.

Tầm quan trọng của dung lượng RAM trong các dự án lớn.

Đối với mày tính nói chung, RAM là bộ nhớ để lưu trữ thông tin và các kết quả tính toán  Khi máy tính thực hiện nhiều công việc khác nhau, RAM sẽ tiêu tốn nhiều hơn. 

Trở lại với arduino, sau khi thông thạo với phiên bản basic Arduino UNO R3, nhiều bạn đã lựa chọn arduino mega là trải nghiệm tiếp theo vì nó có nhiều thứ mà họ đang cần, trong đó RAM là tiêu chí không thể bỏ qua.

Arduino mega có 8 kbyte RAM , rất nhiều chân IO, ROM, và các chức năng khác nữa.

Chính  lợi thế về số lượng chân IO cho phép ta nâng cấp SRAM ngoài, giao tiếp với tốc độ cực cao.  

Tìm hiểu SRAM UT62256CSCL-70LL

 

Đây là SRAM đơn giản và dễ mua nhất,( nó không phải vi điều khiển).

DATASHEET :https://lib.chipdip.ru/506/DOC001506992.pdf

Chân  Chức năng
Vcc, Vss

Vcc: Nguồn dương

Vss: chính là GND (nguồn âm).

Chú ý : hiệu điện thế nuôi SRAM là 5v DC.

IO (Input/output) Chúng ta đọc và ghi dữ liệu trên RAM tại đây, do đó kích thước tối đa cho 1 lần đọc/ghi là 1 byte (8bit)
A (Adress) Địa chỉ các ô nhớ. Có 15 bit địa chỉ , tương ứng với 215 =32k ô nhớ 1 byte.

WE*,OE*,CE*

3 Chân điều khiển:

 

WE* : Write enable: Kéo chân này xuống Low để ghi dữ liệu
OE* :Output Enable, kéo chân này xuống Low để đọc dữ liệu
CE*:Chip Enable, kéo chân này xuống Low để chọn RAM này (kích hoạt chip)

 

Sơ đồ chân của SRAM (nhìn từ mặt trên)

SRAM này cũng chỉ giống như một ic số, bạn thậm chí còn có thể giao tiếp với ic bằng công tắc thường mà không cần arduino !

Dưới đây là bảng sự thật của ic được mình trích từ datasheet.

Các bạn cần chú ý: việc kéo các chân điều khiển và IO cần phải theo đúng thứ tự mà datasheet yêu cầu, tùy trường hợp mà thứ tự cũng khác nhau.cụ thể:

Để ghi 1 byte

  • b1:Kéo OE lên High, Đầu ra io trên arduino đặt ở OUTPUT, Kéo CE xuống low.
  • b2: Kéo các chân địa chỉ.
  • b3:Kéo WE để đẩy dữ liệu vào trong. (io trên ram là Input)
  • b4:  rồi kéo io trên arduino để đặt dữ liệu
  • b5:kết thúc hoặc tiếp tục, nếu tiếp tục thì quay lại bước 2, nếu kết thúc thì dữ WE ở low, CE lên high để khóa ic.

Để đọc 1 byte

  •  b1: Đầu ra io trên arduino đặt ở OUTPUT, Kéo CE xuống low.
  • b2:Kéo các chân địa chỉ.
  • b3:;WE :high, OE low để xuất data.
  • b4: arduino đọc dữ liệu trên các chân io
  • b5: nếu tiếp tục thì quay lại bước 2, nếu kết thúc thì kéo  WE ở low, CE lên high để khóa ic.

 Như vậy quy tắc là

Khi các chân địa chỉ thay đổi thì WE và OE cần phải ở chế độ khóa (High),  sau khi chuẩn bị xong address ta mở khóa các chânWE hoặc OE rồi mới thực hiện đọc/ ghi trên các chân I/O.

Sử dụng UT62256C này với arduino.

Mình sẽ cố gắng hướng dẫn chi tiết để các bạn có thể tự tay độ RAM cho arduino của mình, trước tiên chúng ta cần chuẩn bị:

  • 1 arduino mega 2560
  • 1 Sram UT62256C loại 28 chân.
  • 1 pcb chuyển đổi SOP-> DIP 28
  • 1 thanh jumper đực đôi 36 chân. 
  • 1 ít dây mềm, máy hàn...

 

 

Tất cả chỉ có vậy, cũng không hẳn là phức tạp nên phần này chủ yếu cần sự khéo tay của các bạn.

Mình đã cố gắng sắp xếp vị trí port trên arduino để giảm thiểu nhiều nhất các chân thường dùng quan trọng, mình nhắm tới các pin cuối cùng .

Hãy nối dây với arduino và SRAM theo sơ đồ dưới đây.

Đây là mạch của mình ^^

Lưu ý

Vì mối hàn khá nhỏ , các mối gần nhau rất dễ chạm chập, hãy kiểm tra lại mạch thật kỹ trước khi tiếp tục..

Giao tiếp với arduino.

Việc điều khiển các chân IO trên arduino để giao tiếp với SRAM rất cần đến tốc độ, nên thay vì sử dụng digitalWrite/Read thì mình sẽ kích hoạt trực tiếp lên các chân port của vi điều khiển ATMEGA 2560.

Điều khiển port rất đơn giản, các bạn có thể xem lại bài viết của mình ở ĐÂY và ở ĐÂY

Theo như quy tắc của bảng sự thật , chúng ta xây dựng hai hàm WRITE/READ đơn giản như sau .


void SRAM_SET_PORT()
{
    // Hàm này để cài đặt pin ra cho arduino
    DDRA = DDRA | B11111111; // từ pin 0 -> pin 6 là output
    DDRC = DDRC | B11111111; // tất cả
    DDRB = DDRB | B00000111; // 3 PORT ĐẦU

    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa

    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //=PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //=PORTC&B00000000;
    delayMicroseconds(10);
}
void SRAM_WRITE_1_BYTE(uint16_t adress, uint8_t value_1_byte)
{
    // ghi vào Sram 1 byte nhớ tại địa chỉ "adress"
    //B1: chuẩn bị địa chỉ trước

    DDRL = 255; //=B11111111 : đặt đầu ra I/O là out put

    // MỞ IC CHÂN CE
    PORTB = PORTB & B11111011; // read : CE low

    uint8_t bit_8_cao = (uint8_t)((adress >> 8) & 0xFF);
    uint8_t bit_8_thap = (uint8_t)(adress & 0xFF);
    PORTA = PORTA | bit_8_cao;
    PORTC = PORTC | bit_8_thap;
    //B2: MỞ cổng write

    // delayMicroseconds(10);
    PORTB = PORTB & B11111110; // read :  WE xuống low
    // WE :high không quan tâm

    // delayMicroseconds(10);
    // b3 : shift out:
    PORTL = value_1_byte;
    PORTL = value_1_byte;
    // phần này nếu ic chậm thì cần đợi 1 lúc trước khi đóng ic

    //b4 :đóng ic
    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa
    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //PORTC&B00000000;
}
uint8_t SRAM_READ_1_BYTE(uint16_t adress)
{
    //B1: chuẩn bị địa chỉ trước

    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    // MỞ IC CHÂN CE
    PORTB = PORTB & B11111011; // read : CE low
    // delayMicroseconds(10);
    uint8_t bit_8_cao = (uint8_t)((adress >> 8) & 0xFF);
    uint8_t bit_8_thap = (uint8_t)(adress & 0xFF);
    PORTA = PORTA | bit_8_cao;
    PORTC = PORTC | bit_8_thap;
    //B2 : MỞ CỔNG READ

    PORTB = PORTB | B00000001; // WE :high
    PORTB = PORTB & B11111001; // read : CE low, OE low

    // delayMicroseconds(10);
    //B3: SHIFT IN

    uint8_t Read_port = PINL;
    Read_port = PINL;
    //B4: KHÓA

    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa
    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //=PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //=PORTC&B00000000;
    return (uint8_t)Read_port;
}

void setup()
{
    SRAM_SET_PORT();
    Serial.begin(9600);
}

void loop()
{
    SRAM_WRITE_1_BYTE(1000, 123); // ghi giá trị 123 tại ô nhớ 1000
    byte gia_tri = SRAM_READ_1_BYTE(1000); // xuất giá trị tại ô 1000
    Serial.println(gia_tri);
}

Kết quả nè:

Như vậy với 15 bit địa chỉ thì giá trị ô nhớ sẽ từ : 0 đến 32767.

Mỗi lần ghi thì ta chỉ ghi được 1 byte dữ liệu,  quy tắc ghi cũng giống hệt với EEPROM

  • Gỉa sử địa chỉ mà chúng ta muốn lưu là ô 500, khi dùng để lưu một biến có cỡ 2byte thì ô 501 nghiễm nhiên đã bị sử dụng để lưu 8 bit còn lại, do đó, mặc định bạn không được dùng ô 501 để làm địa chỉ lưu , mà phải bắt đầu từ ô 502, bạn nhớ nhé.
  • Phải xem sét việc ghi nhiều byte có đang ghi trùng lên các ô khác hay không.  Ví dụ ô 500 đã có dũ liệu, ta dùng ô 488 để lưu 4 byte, việc này sẽ ghi đè dữ liệu vào ô  500, gây sai lệch.
  • Kích cỡ lưu trữ của biến trên arduino và arduino mega khác nhau, Ví dụ kiểu double trên uno là 4 bytes nhưng trên arduino due là 8 bytes, do đó kích cỡ để lưu cũng khác. 

Xem thêm:  http://arduino.vn/tutorial/1370-huong-dan-su-dung-ic-eeprom-24cxx-cua-atmel-va-thu-vien#index23

Cách lưu số lớn hơn kiểu byte (>255) vào eeprom và SRAM

Chúng ta còn có thể lưu 1 kiểu số bất kỳ như byte, long double, float, char ..vv vào RAM (hoặc EEPROM) bằng việc tách và ghép các byte lưu trữ .

Hãy tham khảo code bên dưới:

void SRAM_SET_PORT()
{
    // Hàm này để cài đặt pin ra cho arduino
    DDRA = DDRA | B11111111; // từ pin 0 -> pin 6 là output
    DDRC = DDRC | B11111111; // tất cả
    DDRB = DDRB | B00000111; // 3 PORT ĐẦU

    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa

    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //=PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //=PORTC&B00000000;
    delayMicroseconds(10);
}
void SRAM_WRITE_1_BYTE(uint16_t adress, uint8_t value_1_byte)
{
    // ghi vào Sram 1 byte nhớ tại địa chỉ "adress"
    //B1: chuẩn bị địa chỉ trước

    DDRL = 255; //=B11111111 : đặt đầu ra I/O là out put

    // MỞ IC CHÂN CE
    PORTB = PORTB & B11111011; // read : CE low

    uint8_t bit_8_cao = (uint8_t)((adress >> 8) & 0xFF);
    uint8_t bit_8_thap = (uint8_t)(adress & 0xFF);
    PORTA = PORTA | bit_8_cao;
    PORTC = PORTC | bit_8_thap;
    //B2: MỞ cổng write

    // delayMicroseconds(10);
    PORTB = PORTB & B11111110; // read :  WE xuống low
    // WE :high không quan tâm

    // delayMicroseconds(10);
    // b3 : shift out:
    PORTL = value_1_byte;
    PORTL = value_1_byte;
    // phần này nếu ic chậm thì cần đợi 1 lúc trước khi đóng ic

    //b4 :đóng ic
    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa
    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //PORTC&B00000000;
}
uint8_t SRAM_READ_1_BYTE(uint16_t adress)
{
    //B1: chuẩn bị địa chỉ trước

    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    // MỞ IC CHÂN CE
    PORTB = PORTB & B11111011; // read : CE low
    // delayMicroseconds(10);
    uint8_t bit_8_cao = (uint8_t)((adress >> 8) & 0xFF);
    uint8_t bit_8_thap = (uint8_t)(adress & 0xFF);
    PORTA = PORTA | bit_8_cao;
    PORTC = PORTC | bit_8_thap;
    //B2 : MỞ CỔNG READ

    PORTB = PORTB | B00000001; // WE :high
    PORTB = PORTB & B11111001; // read : CE low, OE low

    // delayMicroseconds(10);
    //B3: SHIFT IN

    uint8_t Read_port = PINL;
    Read_port = PINL;
    //B4: KHÓA

    PORTB = PORTB | B00000111; // stand_byte : về trạng thái khóa
    DDRL = 0; //=B00000000 : đặt đầu ra I/O là in put
    PORTA = 0; //=PORTA&B00000000;// RESET XUỐNG 0
    PORTC = 0; //=PORTC&B00000000;
    return (uint8_t)Read_port;
}
template <class T>int RAM_WRITE(uint16_t adress, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
        SRAM_WRITE_1_BYTE(adress + i, *p++);
    return i;
}

template <class T>int RAM_READ(uint16_t adress, T& value)
{
    byte* p = (byte*)(void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
        *p++ = SRAM_READ_1_BYTE(adress + i);
    return i;
}

void setup()
{
    SRAM_SET_PORT();
    Serial.begin(9600);
}
int INT = -1233, i = 0;
float FLOAT = 134.344, f = 0;
double DOUBLE = 123.966, d = 0;
long LONG = 123343545, l = 0;
byte BYTE = 93, b = 0;
char CHAR = 'g', c = 0;
//

void loop()
{
    //ghi
    RAM_WRITE(0, INT); //2 byte (ghi 2 ô :0,1)
    RAM_WRITE(2, FLOAT); //4 byte (ghi 4 ô: 2,3,4,5)
    RAM_WRITE(6, DOUBLE); //4 byte (ghi 4 ô: 6,7,8,9)
    RAM_WRITE(10, LONG); //4 byte(ghi 4 ô: 10 -> 13)
    RAM_WRITE(14, BYTE); //1 byte(ghi 1 ô:14)
    RAM_WRITE(15, CHAR); //1 byte(ghi 4 ô: 15)
    //đọc
    RAM_READ(0, i);
    RAM_READ(2, f);
    RAM_READ(6, d);
    RAM_READ(10, l);
    RAM_READ(14, b);
    RAM_READ(15, c);
    //in
    Serial.println(i);
    Serial.println(f, 5);
    Serial.println(d, 5);
    Serial.println(l);
    Serial.println(b);
    Serial.println(c);
    Serial.println("_____");
}

Bạn muốn nhiều RAM hơn nữa.?!

Có 2 cách để nâng thêm RAM.

  • Cách 1: Bạn đã biết chân CE trên Sram dùng để kích hoạt IC, khi muốn sử dụng thêm 2 hoặc nhiều hơn module SRAM  này, hãy nối song song tất cả các chân của IC 1 với IC2 (theo đúng thứ tự) với nhau, riêng chân CE của IC2 thì nối riêng với 1 chân điều khiển khác (tạm gọi là chân chọn chip 2) trên arduino. Khi muốn lưu trên IC nào  thì kéo CE của IC đó xuống Low chân CE của các IC còn lại thì kéo lên High. 
  • Cách 2: Mua IC có dung lượng cao hơn, chỉ tăng thêm số chân địa chỉ, khi đó cách dùng cũng tương tự .

Chọn một ic khác :

ic Sram 23LC1024 sẽ cho phép bạn nâng 128kbyte, đọc theo bài viết link phía dưới

http://arduino.vn/tutorial/1873-nang-128kbyte-sram-ngoai-cho-arduino-voi-ic-23lc1024 

Test.

//CODE TEST SRAM TRONG VIDEO
// Mình đã lược bớt 4 hàm phía trên , các bạn nhớ copy thêm vào nhé!
void write_abc(uint16_t i, uint16_t val)
{
    uint16_t size_v = 2; // 2 byte
    i *= size_v;
    RAM_WRITE(i, val);
}
uint16_t read_abc(uint16_t i)
{
    uint16_t size_v = 2; // 2 byte
    uint16_t val = 0;
    i *= size_v;
    RAM_READ(i, val);
    return val;
}

void setup()
{
    SRAM_SET_PORT();
    Serial.begin(9600);
    uint16_t i = 0;
    for (i = 0; i < 16000; i++) {
        write_abc(i, i);
    }
    for (i = 0; i < 16000; i++) {
        uint16_t val = read_abc(i);
        Serial.println(val);
    }
}
void loop()
{
}

Trong video nếu sửa lại đúng thì là : "nó lưu hết 32000 ô nhớ cho 16000 biến 2 byte ! "

Không chỉ là ước mơ.

Cái hay của RAM ngoài đó là khi bạn reset lại arduino thì dữ liệu trên RAM sẽ không bị mất.

Hy vọng qua bài này, các bạn sẽ tự tin hơn về dung lượng còn khiêm tốn của arduino mega. Có thể tự xây dựng một dàn arduino cấu hình khủng khi nâng thêm EEPROM cho ẻm. 

Đó mới chỉ là 32kbyte, vậy còn nâng thêm 1 Mega byte thì sao nhỉ ?

<Thái Sơn><Đừng quên nhấn like ủng hộ nhé mọi người>

lên
17 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

lên
34 thành viên đã đánh giá bài viết này hữu ích.
Các bài viết cùng tác giả

ST7565 | Chuyển động trong lập trình Game và đồ họa | Phần 2

Trong bài viết trước, chúng ta đã cùng tìm hiểu một vài nguyên tắc của hiệu ứng chuyển động trong đồ họa. Bài viết này sẽ nối tiếp nội dung còn dở dang của bài trước, hãy cùng đi tiếp nào. Tất nhiên là trên arduino cùng lcd st7565 rồi.cheekyblush

lên
10 thành viên đã đánh giá bài viết này hữu ích.

AVR-Xuất xung với tần số và độ rộng theo ý muốn

Tiếp tục chuỗi bài: Điều khiển pin bằng ngôn ngữ chính thống. 

Bài viết này sẽ giúp bạn tạo một xung PWM có tần số và độ rộng xung theo ý muốn. 

lên
29 thành viên đã đánh giá bài viết này hữu ích.